{
  "openapi": "3.1.0",
  "info": {
    "title": "BigShop AI Platform API",
    "version": "1.0.0",
    "description": "Enterprise REST API for BigShop truck and fleet repair management platform. Built for autonomous AI agents, integrators, and auto shop workflows.\n\nAgents: create a READ-ONLY API key (Admin > API Keys > Access: Read-only). It can call GET endpoints only; writes are refused with 403 before they reach BigShop, credentials and sharing links are never returned, and employee pay endpoints stay hidden unless the key was created with includePayData. Each GET operation carries x-read-only-key: allowed | with-includePayData | never. Money is integer cents unless an operation's x-money-units says otherwise; report endpoints in particular mix dollars and cents. Dates are shop-local YYYY-MM-DD.",
    "contact": {
      "name": "BigShop Support",
      "url": "https://bigshopai.com",
      "email": "support@bigshopai.com"
    }
  },
  "servers": [
    {
      "url": "https://api.bigshopai.com/v1",
      "description": "Production API Server"
    }
  ],
  "security": [
    { "ApiKeyAuth": [] },
    { "BearerAuth": [] }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "API Key formatted as 'ApiKey <your_api_key>' (or passed via 'X-Api-Key: <key>'). A key is either read_only (GET/HEAD only) or full (tenant admin). Keys created through POST /api-keys without accessLevel are full."
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Cognito User JWT access token"
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Unique key (8–128 characters, e.g. UUID) to ensure safe retries without duplicating operations.",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 128
        }
      },
      "AgentNameHeader": {
        "name": "X-Agent-Name",
        "in": "header",
        "required": false,
        "description": "Name and version of the calling AI agent (e.g. 'AsaDealerBot/2.1') for attribution in shop audit trails.",
        "schema": {
          "type": "string",
          "maxLength": 100
        }
      },
      "AgentRunIdHeader": {
        "name": "X-Agent-Run-Id",
        "in": "header",
        "required": false,
        "description": "Execution run ID or trace ID of the calling AI agent for diagnostics.",
        "schema": {
          "type": "string",
          "maxLength": 100
        }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": ["error", "message"],
        "properties": {
          "error": { "type": "string", "example": "VALIDATION_ERROR" },
          "message": { "type": "string", "example": "The request is not valid. Nothing was created." },
          "details": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": { "type": "string" },
                "message": { "type": "string" }
              }
            }
          },
          "nextStep": { "type": "string", "nullable": true },
          "candidates": { "type": "array", "items": { "type": "object" } }
        }
      },
      "Customer": {
        "type": "object",
        "required": ["id", "name"],
        "properties": {
          "id": { "type": "string", "example": "cust_12345" },
          "name": { "type": "string", "example": "ABC Trucking LLC" },
          "email": { "type": "string", "format": "email", "example": "contact@abc.com" },
          "phone": { "type": "string", "example": "+15551234567" },
          "companyName": { "type": "string" },
          "dotNumber": { "type": "string" },
          "address": { "type": "string" },
          "notes": { "type": "string" },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "Vehicle": {
        "type": "object",
        "required": ["id", "vin"],
        "properties": {
          "id": { "type": "string", "example": "veh_456" },
          "vin": { "type": "string", "example": "1FUJGBDV8LN123456" },
          "unitNumber": { "type": "string", "example": "Unit 14" },
          "make": { "type": "string", "example": "Freightliner" },
          "model": { "type": "string", "example": "Cascadia" },
          "year": { "type": "integer", "example": 2022 },
          "licensePlate": { "type": "string", "example": "TX-9988" },
          "customerId": { "type": "string", "example": "cust_12345" },
          "mileage": { "type": "number", "example": 185420 }
        }
      },
      "InventoryItem": {
        "type": "object",
        "required": ["id", "partNumber", "name"],
        "properties": {
          "id": { "type": "string", "example": "part_789" },
          "partNumber": { "type": "string", "example": "FL-1002" },
          "name": { "type": "string", "example": "Heavy Duty Oil Filter" },
          "description": { "type": "string" },
          "category": { "type": "string", "example": "filters" },
          "quantity": { "type": "number", "example": 12 },
          "unitCostCents": { "type": "integer", "example": 1250, "description": "Unit cost in whole integer cents ($12.50)" },
          "unitPriceCents": { "type": "integer", "example": 2400, "description": "Retail price in whole integer cents ($24.00)" },
          "reorderPoint": { "type": "number", "example": 4 },
          "binLocation": { "type": "string", "example": "A-12-B" },
          "vendorId": { "type": "string" },
          "vendorName": { "type": "string" }
        }
      },
      "ReceivingLine": {
        "type": "object",
        "required": ["partNumber", "quantity", "unitCostCents"],
        "properties": {
          "partNumber": { "type": "string", "maxLength": 64, "example": "FL-1002" },
          "description": { "type": "string", "maxLength": 255, "example": "Oil filter" },
          "quantity": { "type": "number", "minimum": 0.0001, "maximum": 1000000, "example": 2 },
          "unitCostCents": { "type": "integer", "minimum": 0, "maximum": 100000000, "example": 1250, "description": "Exact whole cents ($12.50 = 1250)" },
          "vendorPartNumber": { "type": "string", "maxLength": 64, "example": "FL-A100" },
          "note": { "type": "string", "maxLength": 500 }
        }
      },
      "ReceivingRequest": {
        "type": "object",
        "required": ["invoiceNumber", "lines"],
        "properties": {
          "invoiceNumber": { "type": "string", "maxLength": 64, "example": "INV-1042" },
          "invoiceDate": { "type": "string", "format": "date", "example": "2026-10-01" },
          "mode": { "type": "string", "enum": ["draft", "receive"], "default": "draft" },
          "purchaseOrderId": { "type": "string", "description": "Optional: link directly to an existing PO by ID" },
          "purchaseOrderNumber": { "type": "string", "description": "Optional: link directly to an existing PO by human number (e.g. 'PO-104')" },
          "vendor": {
            "type": "object",
            "properties": {
              "id": { "type": "string", "description": "Existing vendor ID" },
              "name": { "type": "string", "description": "Vendor name (auto-matched or created)" },
              "accountNumber": { "type": "string" },
              "createIfMissing": { "type": "boolean", "default": true }
            }
          },
          "note": { "type": "string", "maxLength": 500 },
          "lines": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ReceivingLine" },
            "minItems": 1,
            "maxItems": 100
          }
        }
      },
      "ReceivingResponse": {
        "type": "object",
        "properties": {
          "mode": { "type": "string", "enum": ["draft", "receive"] },
          "status": { "type": "string", "enum": ["pending_review", "received", "received_with_issues", "receive_failed"] },
          "purchaseOrder": {
            "type": "object",
            "properties": {
              "id": { "type": "string" },
              "number": { "type": "string" },
              "status": { "type": "string" },
              "vendorId": { "type": "string", "nullable": true },
              "vendorName": { "type": "string", "nullable": true },
              "vendorInvoiceNumber": { "type": "string" },
              "totalCostCents": { "type": "integer" },
              "lineCount": { "type": "integer" },
              "linkedExistingPo": { "type": "boolean" }
            }
          },
          "vendor": {
            "type": "object",
            "properties": {
              "id": { "type": "string", "nullable": true },
              "name": { "type": "string", "nullable": true },
              "created": { "type": "boolean" },
              "matchedBy": { "type": "string", "enum": ["id", "name", "created", "unlinked", "none"] }
            }
          },
          "lines": { "type": "array", "items": { "type": "object" } },
          "warnings": { "type": "array", "items": { "type": "object" } },
          "partialFailure": { "type": "boolean" },
          "failures": { "type": "array", "items": { "type": "object" } },
          "nextStep": { "type": "string", "nullable": true }
        }
      },
      "WorkOrder": {
        "type": "object",
        "required": ["id", "orderNumber", "status"],
        "properties": {
          "id": { "type": "string", "example": "wo_9988" },
          "orderNumber": { "type": "string", "example": "WO-1042" },
          "customerId": { "type": "string" },
          "customerName": { "type": "string" },
          "vehicleId": { "type": "string" },
          "vehicleUnit": { "type": "string" },
          "status": { "type": "string", "enum": ["draft", "estimate", "approved", "in_progress", "completed", "invoiced", "paid", "cancelled"] },
          "priority": { "type": "string", "enum": ["low", "medium", "high", "urgent"] },
          "complaint": { "type": "string" },
          "totalCostCents": { "type": "integer" },
          "totalPriceCents": { "type": "integer" },
          "services": { "type": "array", "items": { "type": "object" } },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "ServiceRequest": {
        "type": "object",
        "required": ["id", "status"],
        "properties": {
          "id": { "type": "string", "example": "sr_3321" },
          "status": { "type": "string", "enum": ["new", "reviewed", "scheduled", "converted", "rejected"] },
          "customerName": { "type": "string" },
          "phone": { "type": "string" },
          "email": { "type": "string" },
          "vehicleVin": { "type": "string" },
          "description": { "type": "string" },
          "preferredDate": { "type": "string", "format": "date" },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "PurchaseOrder": {
        "type": "object",
        "required": ["id", "number", "status"],
        "properties": {
          "id": { "type": "string", "example": "po_98765" },
          "number": { "type": "string", "example": "PO-104" },
          "status": {
            "type": "string",
            "enum": ["draft", "ordered", "partially_received", "received", "fully_received", "cancelled"],
            "example": "ordered"
          },
          "vendorId": { "type": "string", "example": "vend_123" },
          "vendorName": { "type": "string", "example": "FleetPride" },
          "vendorInvoiceNumber": { "type": "string", "example": "INV-55441" },
          "vendorInvoiceNumbers": { "type": "array", "items": { "type": "string" } },
          "type": { "type": "string", "enum": ["purchase", "return"], "default": "purchase" },
          "note": { "type": "string" },
          "parts": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/PurchaseOrderPart" }
          },
          "itemCount": { "type": "integer", "example": 1 },
          "totalAmount": { "type": "number", "example": 262.00 },
          "totalCostCents": { "type": "integer", "example": 26200 },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "PurchaseOrderPart": {
        "type": "object",
        "required": ["partNumber", "quantity"],
        "properties": {
          "id": { "type": "string" },
          "partNumber": { "type": "string", "example": "BWP-M-1234" },
          "description": { "type": "string", "example": "Brake Shoe Kit" },
          "quantity": { "type": "number", "example": 4 },
          "quantityReceived": { "type": "number", "example": 0 },
          "unitCost": { "type": "number", "example": 65.50 },
          "unitCostCents": { "type": "integer", "example": 6550 },
          "totalCostCents": { "type": "integer", "example": 26200 },
          "vendorPartNumber": { "type": "string" },
          "status": { "type": "string", "example": "ordered" }
        }
      },
      "WebhookSubscription": {
        "type": "object",
        "required": ["id", "tenantId", "name", "url", "events", "isActive", "createdAt"],
        "properties": {
          "id": { "type": "string", "example": "wh_45892" },
          "tenantId": { "type": "string", "example": "tenant_123" },
          "name": { "type": "string", "example": "ERP Integration Sync" },
          "url": { "type": "string", "format": "uri", "example": "https://api.example.com/webhooks" },
          "events": {
            "type": "array",
            "items": { "type": "string" },
            "example": ["service_request.created", "sales_order.completed", "purchase_order.received"]
          },
          "isActive": { "type": "boolean", "example": true },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" },
          "lastDeliveryStatus": { "type": "string", "enum": ["success", "failed"] },
          "lastDeliveryAt": { "type": "string", "format": "date-time" },
          "secret": { "type": "string", "description": "Unmasked signing secret returned only upon creation or secret rotation.", "example": "whsec_..." }
        }
      },
      "WebhookEventInfo": {
        "type": "object",
        "required": ["type", "description", "category"],
        "properties": {
          "type": { "type": "string", "example": "service_request.created" },
          "description": { "type": "string", "example": "Triggered when a digital check-in or customer service request is submitted." },
          "category": { "type": "string", "enum": ["service_requests", "counter_sales", "work_orders", "billing", "inventory", "purchasing", "customers", "system"], "example": "service_requests" }
        }
      },
      "ApiErrorBody": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Short error label or message."
          },
          "message": {
            "type": "string",
            "description": "Human-readable detail. Present on report-aggregates and shared work-order-service errors; absent on digest errors and on dashboard trend-aggregates errors."
          },
          "path": {
            "type": "string",
            "description": "Echoed request path (only on the report-aggregates 404 body)."
          }
        },
        "required": [
          "error"
        ],
        "description": "Error body. Shape differs slightly by service; only `error` is guaranteed."
      },
      "PermissionDeniedResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Always PERMISSION_DENIED.",
            "enum": [
              "PERMISSION_DENIED"
            ]
          },
          "message": {
            "type": "string",
            "description": "Names the missing permission."
          },
          "missingPermissions": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Permission key, e.g. reports:operational"
            }
          }
        },
        "required": [
          "error",
          "message",
          "missingPermissions"
        ]
      },
      "ReportPeriod": {
        "type": "object",
        "properties": {
          "startDate": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "First day of the range (shop-local, inclusive)."
          },
          "endDate": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Last day of the range (shop-local, inclusive)."
          }
        },
        "required": [
          "startDate",
          "endDate"
        ]
      },
      "DailyReportAggregate": {
        "type": "object",
        "properties": {
          "tenantId": {
            "type": "string",
            "description": "Shop (tenant) id."
          },
          "date": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Shop-local calendar day this row covers."
          },
          "laborRevenueCents": {
            "type": "integer",
            "description": "Labor revenue on invoices dated this day. Integer cents.",
            "x-unit": "cents"
          },
          "partsRevenueCents": {
            "type": "integer",
            "description": "Parts revenue (work-order parts plus counter-sale parts). Integer cents.",
            "x-unit": "cents"
          },
          "tiresRevenueCents": {
            "type": "integer",
            "description": "Tire revenue. Integer cents.",
            "x-unit": "cents"
          },
          "subcontractsCents": {
            "type": "integer",
            "description": "Subcontract / sublet revenue. Integer cents.",
            "x-unit": "cents"
          },
          "shopSuppliesCents": {
            "type": "integer",
            "description": "Shop supplies / materials revenue. Integer cents.",
            "x-unit": "cents"
          },
          "feesCents": {
            "type": "integer",
            "description": "Fee revenue (excludes EPA and catalog service items). Integer cents.",
            "x-unit": "cents"
          },
          "epaCents": {
            "type": "integer",
            "description": "EPA / environmental fee, its own bucket since 2026-07. Absent on older rows (read as 0). Integer cents.",
            "x-unit": "cents"
          },
          "serviceItemsCents": {
            "type": "integer",
            "description": "Catalog service items bucket. Absent on older rows (read as 0). Integer cents.",
            "x-unit": "cents"
          },
          "discountsCents": {
            "type": "integer",
            "description": "Discounts applied. Integer cents.",
            "x-unit": "cents"
          },
          "taxesCents": {
            "type": "integer",
            "description": "Sales tax billed on the day's invoices (work orders plus counter sales). Integer cents.",
            "x-unit": "cents"
          },
          "totalRevenueCents": {
            "type": "integer",
            "description": "Invoice grand total for the day (work orders plus counter sales). Card surcharge is NOT included. Integer cents.",
            "x-unit": "cents"
          },
          "laborCostCents": {
            "type": "integer",
            "description": "Labor cost of sales. Absent on rows written before cost enrichment (read as 0). Integer cents.",
            "x-unit": "cents"
          },
          "partsCostCents": {
            "type": "integer",
            "description": "Parts cost of sales. Absent on older rows. Integer cents.",
            "x-unit": "cents"
          },
          "tiresCostCents": {
            "type": "integer",
            "description": "Tire cost of sales. Absent on older rows. Integer cents.",
            "x-unit": "cents"
          },
          "materialsCostCents": {
            "type": "integer",
            "description": "Shop-supplies / materials cost. Absent on older rows. Integer cents.",
            "x-unit": "cents"
          },
          "subcontractsCostCents": {
            "type": "integer",
            "description": "Subcontract cost. Absent on older rows. Integer cents.",
            "x-unit": "cents"
          },
          "surchargeCents": {
            "type": "integer",
            "description": "Card surcharge collected on the day's invoices (pass-through, outside totalRevenueCents). Absent on older rows. Integer cents.",
            "x-unit": "cents"
          },
          "paidSurchargeCents": {
            "type": "integer",
            "description": "Card surcharge on fully paid invoices. Absent on older rows. Integer cents.",
            "x-unit": "cents"
          },
          "salesOrderRevenueCents": {
            "type": "integer",
            "description": "Counter-sale (sales order) revenue. A SUBSET of totalRevenueCents, and its lines are also inside the category buckets above. Integer cents.",
            "x-unit": "cents"
          },
          "salesOrderTaxesCents": {
            "type": "integer",
            "description": "Counter-sale portion of taxesCents. Integer cents.",
            "x-unit": "cents"
          },
          "paidSalesOrderRevenueCents": {
            "type": "integer",
            "description": "Counter-sale revenue on paid sales orders. Integer cents.",
            "x-unit": "cents"
          },
          "salesOrderCostCents": {
            "type": "integer",
            "description": "Counter-sale cost of goods. Absent on older rows. Integer cents.",
            "x-unit": "cents"
          },
          "unitemizedRevenueCents": {
            "type": "integer",
            "description": "Invoiced revenue that produced no category line at all (a total with nothing itemized). Inside totalRevenueCents but outside the category buckets. Integer cents.",
            "x-unit": "cents"
          },
          "paidLaborRevenueCents": {
            "type": "integer",
            "description": "Labor revenue on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paidPartsRevenueCents": {
            "type": "integer",
            "description": "Parts revenue on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paidTiresRevenueCents": {
            "type": "integer",
            "description": "Tire revenue on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paidSubcontractsCents": {
            "type": "integer",
            "description": "Subcontract revenue on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paidShopSuppliesCents": {
            "type": "integer",
            "description": "Shop supplies revenue on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paidFeesCents": {
            "type": "integer",
            "description": "Fee revenue on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paidEpaCents": {
            "type": "integer",
            "description": "EPA fee on fully paid invoices. Absent on older rows. Integer cents.",
            "x-unit": "cents"
          },
          "paidServiceItemsCents": {
            "type": "integer",
            "description": "Service items on fully paid invoices. Absent on older rows. Integer cents.",
            "x-unit": "cents"
          },
          "paidDiscountsCents": {
            "type": "integer",
            "description": "Discounts on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paidTaxesCents": {
            "type": "integer",
            "description": "Tax on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paidTotalRevenueCents": {
            "type": "integer",
            "description": "Grand total of fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paymentTotalCents": {
            "type": "integer",
            "description": "Payments received on this day, net of refunds and voids. Integer cents.",
            "x-unit": "cents"
          },
          "laborHoursTotal": {
            "type": "number",
            "description": "Total billed labor hours on invoiced orders that day, including lines with no technician named; declined work excluded. Absent on older rows. Differs from the sum of technicianStats[].laborHours, which counts only hours attributed to a named technician.",
            "x-unit": "hours"
          },
          "invoiceCount": {
            "type": "integer",
            "description": "Invoices dated this day (invoiced work orders plus counter sales)."
          },
          "paidInvoiceCount": {
            "type": "integer",
            "description": "Of those, fully paid."
          },
          "unpaidInvoiceCount": {
            "type": "integer",
            "description": "Of those, not fully paid."
          },
          "paymentCount": {
            "type": "integer",
            "description": "Payment transactions received that day (refund rows and voided payments are not counted)."
          },
          "paymentsByMethod": {
            "type": "object",
            "properties": {},
            "description": "Net payments by method, in integer cents. Keys are the payment-method labels as recorded (free-form, e.g. Cash, Check, Credit Card; Other when none was recorded).",
            "additionalProperties": {
              "type": "integer",
              "x-unit": "cents"
            }
          },
          "uniqueCustomerCount": {
            "type": "integer",
            "description": "Distinct customers on the day's invoices and payments. Always exact."
          },
          "customerIds": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Customer id."
            },
            "description": "Persisted customer id list. Capped to keep the row under the storage limit; see customerIdsTruncated."
          },
          "customerIdsTruncated": {
            "type": "boolean",
            "description": "True when customerIds was capped and is not exhaustive."
          },
          "uniqueVehicleCount": {
            "type": "integer",
            "description": "Distinct vehicles on the day's invoices. Absent on older rows."
          },
          "vehicleIds": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Vehicle id."
            }
          },
          "technicianStats": {
            "type": "object",
            "properties": {},
            "description": "Per-technician stats for the day, keyed by technician (user) id.",
            "additionalProperties": {
              "$ref": "#/components/schemas/TechnicianDailyStats"
            }
          },
          "updatedAt": {
            "type": "string",
            "description": "When the row was last written.",
            "format": "date-time"
          }
        },
        "required": [
          "date",
          "invoiceCount",
          "totalRevenueCents",
          "paymentTotalCents"
        ],
        "description": "One stored per-day aggregate row, returned as stored. All *Cents fields are integer cents. Invoices are bucketed by invoiced date and payments by payment date, both converted to the shop's local calendar day. Days with no stored row are omitted from API responses (not zero-filled)."
      },
      "TechnicianDailyStats": {
        "type": "object",
        "properties": {
          "technicianId": {
            "type": "string",
            "description": "Technician (user) id."
          },
          "technicianName": {
            "type": "string",
            "description": "Technician name as of the invoice."
          },
          "laborHours": {
            "type": "number",
            "description": "Billed labor hours attributed to this technician.",
            "x-unit": "hours"
          },
          "laborRevenueCents": {
            "type": "integer",
            "description": "Labor revenue attributed to this technician (net of per-line discounts). Integer cents.",
            "x-unit": "cents"
          },
          "jobsCompleted": {
            "type": "integer",
            "description": "Jobs counted for this technician that day."
          },
          "commissionRatePercent": {
            "type": "number",
            "description": "Commission rate in percent (e.g. 20 means 20%).",
            "x-unit": "percent"
          },
          "commissionCents": {
            "type": "integer",
            "description": "Commission earned that day. Integer cents.",
            "x-unit": "cents"
          }
        }
      },
      "DailyAggregatesResponse": {
        "type": "object",
        "properties": {
          "aggregates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DailyReportAggregate"
            },
            "description": "Stored daily rows in ascending date order. No cursor: every row in the range is returned in one response."
          },
          "count": {
            "type": "integer",
            "description": "Number of rows returned."
          },
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          }
        },
        "required": [
          "aggregates",
          "count",
          "period"
        ]
      },
      "SalesSummaryAllInvoices": {
        "type": "object",
        "properties": {
          "laborRevenue": {
            "type": "number",
            "description": "Labor revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "partsRevenue": {
            "type": "number",
            "description": "Parts revenue (includes counter-sale parts). Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "tiresRevenue": {
            "type": "number",
            "description": "Tire revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "subcontracts": {
            "type": "number",
            "description": "Subcontract revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "shopSupplies": {
            "type": "number",
            "description": "Shop supplies revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "fees": {
            "type": "number",
            "description": "Fee revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "epa": {
            "type": "number",
            "description": "EPA / environmental fee. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "serviceItems": {
            "type": "number",
            "description": "Catalog service items. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "subtotal": {
            "type": "number",
            "description": "Sum of the eight category lines above. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "discounts": {
            "type": "number",
            "description": "Discounts. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "postDiscountSubtotal": {
            "type": "number",
            "description": "subtotal minus discounts. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "taxes": {
            "type": "number",
            "description": "Sales tax. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "surcharge": {
            "type": "number",
            "description": "Card surcharge collected (pass-through; not included in total). Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "total": {
            "type": "number",
            "description": "Invoice grand total (work orders plus counter sales). Card surcharge is not included. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "invoiceCount": {
            "type": "integer",
            "description": "Number of invoices."
          },
          "laborCost": {
            "type": "number",
            "description": "Labor cost of sales. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "partsCost": {
            "type": "number",
            "description": "Parts cost of sales. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "tiresCost": {
            "type": "number",
            "description": "Tire cost of sales. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "subcontractsCost": {
            "type": "number",
            "description": "Subcontract cost of sales. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "shopSuppliesCost": {
            "type": "number",
            "description": "Shop supplies cost (the day's materials cost). Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          }
        },
        "description": "Totals across every invoice dated in the range. Money fields are DOLLARS."
      },
      "SalesSummaryPaidInvoices": {
        "type": "object",
        "properties": {
          "laborRevenue": {
            "type": "number",
            "description": "Labor revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "partsRevenue": {
            "type": "number",
            "description": "Parts revenue (includes counter-sale parts). Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "tiresRevenue": {
            "type": "number",
            "description": "Tire revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "subcontracts": {
            "type": "number",
            "description": "Subcontract revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "shopSupplies": {
            "type": "number",
            "description": "Shop supplies revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "fees": {
            "type": "number",
            "description": "Fee revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "epa": {
            "type": "number",
            "description": "EPA / environmental fee. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "serviceItems": {
            "type": "number",
            "description": "Catalog service items. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "subtotal": {
            "type": "number",
            "description": "Sum of the eight category lines above. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "discounts": {
            "type": "number",
            "description": "Discounts. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "postDiscountSubtotal": {
            "type": "number",
            "description": "subtotal minus discounts. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "taxes": {
            "type": "number",
            "description": "Sales tax. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "surcharge": {
            "type": "number",
            "description": "Card surcharge collected (pass-through; not included in total). Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "total": {
            "type": "number",
            "description": "Invoice grand total (work orders plus counter sales). Card surcharge is not included. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "invoiceCount": {
            "type": "integer",
            "description": "Number of invoices."
          }
        },
        "description": "Same breakdown restricted to fully paid invoices. Money fields are DOLLARS."
      },
      "SalesSummaryTrendPoint": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Shop-local day."
          },
          "invoiced": {
            "type": "number",
            "description": "Invoice total that day. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "payments": {
            "type": "number",
            "description": "Payments received that day (net of refunds and voids). Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "customers": {
            "type": "integer",
            "description": "Distinct customers that day."
          }
        }
      },
      "SalesSummaryDailyPoint": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Shop-local day."
          },
          "invoiced": {
            "type": "number",
            "description": "Invoice grand total that day. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "payments": {
            "type": "number",
            "description": "Payments received that day. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "profit": {
            "type": "number",
            "description": "Invoice total minus labor, parts and tire cost only. The total includes sales tax and excludes materials and subcontract cost, so this mirrors the app's trend chart rather than accounting profit. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "customers": {
            "type": "integer",
            "description": "Distinct customers."
          },
          "orders": {
            "type": "integer",
            "description": "Invoice count."
          },
          "paidInvoices": {
            "type": "integer",
            "description": "Fully paid invoice count."
          },
          "paidRevenue": {
            "type": "number",
            "description": "Grand total of fully paid invoices. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "laborRevenue": {
            "type": "number",
            "description": "Labor revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "laborProfit": {
            "type": "number",
            "description": "Labor revenue minus labor cost. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "partsRevenue": {
            "type": "number",
            "description": "Parts revenue with tires folded in. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "partsProfit": {
            "type": "number",
            "description": "Parts-plus-tire revenue minus parts-plus-tire cost. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "laborHours": {
            "type": "number",
            "description": "Billed labor hours summed from technician stats, rounded to 0.1.",
            "x-unit": "hours"
          },
          "billableHours": {
            "type": "number",
            "description": "Same value as laborHours.",
            "x-unit": "hours"
          },
          "avgPerOrder": {
            "type": "number",
            "description": "Invoice total divided by invoice count; 0 when there are no invoices. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          }
        }
      },
      "SalesSummary": {
        "type": "object",
        "properties": {
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          },
          "allInvoices": {
            "$ref": "#/components/schemas/SalesSummaryAllInvoices"
          },
          "paidInvoices": {
            "$ref": "#/components/schemas/SalesSummaryPaidInvoices"
          },
          "payments": {
            "type": "object",
            "properties": {
              "total": {
                "type": "number",
                "description": "Payments received in the range, net of refunds and voids. Dollars as a decimal number (cents divided by 100, not rounded).",
                "x-unit": "dollars"
              },
              "count": {
                "type": "integer",
                "description": "Payment transactions."
              },
              "byMethod": {
                "type": "object",
                "properties": {},
                "description": "Net payments by method label.",
                "additionalProperties": {
                  "type": "number",
                  "x-unit": "dollars"
                }
              }
            }
          },
          "uniqueCustomers": {
            "type": "integer",
            "description": "Distinct customers across the range (union of the per-day customer id lists)."
          },
          "salesOrderRevenue": {
            "type": "number",
            "description": "Counter-sale revenue. It is inside allInvoices.total AND inside the category lines; do not add it on top. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "unitemizedRevenue": {
            "type": "number",
            "description": "Revenue on invoices that produced no category line (total with nothing itemized). Inside total, outside the category lines. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "averageRepairOrder": {
            "type": "number",
            "description": "allInvoices.total divided by invoiceCount; 0 when none. Not rounded to cents. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "trendData": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SalesSummaryTrendPoint"
            },
            "description": "Daily series for the LAST 30 days of the range, zero-filled for days with no activity."
          },
          "trendDataTruncated": {
            "type": "boolean",
            "description": "True when the range is longer than 30 days and trendData holds only the most recent 30."
          },
          "trendDataDays": {
            "type": "integer",
            "description": "Number of points in trendData."
          },
          "requestedRangeDays": {
            "type": "integer",
            "description": "Days in the requested range."
          },
          "trendDaily": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SalesSummaryDailyPoint"
            },
            "description": "Rich per-day series across the WHOLE range, days with data only (no zero-fill), ascending."
          },
          "trendDailyTruncated": {
            "type": "boolean",
            "description": "True when more than 3000 days of data existed and only the most recent 3000 are returned."
          }
        },
        "required": [
          "period",
          "allInvoices",
          "paidInvoices",
          "payments",
          "uniqueCustomers",
          "averageRepairOrder",
          "trendData",
          "trendDataTruncated",
          "trendDataDays",
          "requestedRangeDays",
          "trendDaily",
          "trendDailyTruncated"
        ]
      },
      "SalesSummaryResponse": {
        "type": "object",
        "properties": {
          "summary": {
            "$ref": "#/components/schemas/SalesSummary"
          },
          "dataMode": {
            "type": "string",
            "description": "Which source produced the numbers.",
            "enum": [
              "cached",
              "live"
            ]
          }
        },
        "required": [
          "summary",
          "dataMode"
        ]
      },
      "PaymentsSummary": {
        "type": "object",
        "properties": {
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          },
          "total": {
            "type": "number",
            "description": "Payments received in the range, net of refunds and voids. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "count": {
            "type": "integer",
            "description": "Payment transactions (refund rows and voided payments not counted)."
          },
          "byMethod": {
            "type": "object",
            "properties": {},
            "description": "Net payments by method label as recorded (free-form).",
            "additionalProperties": {
              "type": "number",
              "x-unit": "dollars"
            }
          },
          "dailyTotals": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date",
                  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                  "description": "Shop-local day the payments were received."
                },
                "total": {
                  "type": "number",
                  "description": "Net payments that day. Dollars as a decimal number (cents divided by 100, not rounded).",
                  "x-unit": "dollars"
                },
                "count": {
                  "type": "integer",
                  "description": "Payment transactions that day."
                }
              },
              "required": [
                "date",
                "total",
                "count"
              ]
            },
            "description": "One entry per day that has a stored row, ascending. Days with no stored row are omitted."
          }
        },
        "required": [
          "period",
          "total",
          "count",
          "byMethod",
          "dailyTotals"
        ]
      },
      "PaymentsSummaryResponse": {
        "type": "object",
        "properties": {
          "summary": {
            "$ref": "#/components/schemas/PaymentsSummary"
          },
          "dataMode": {
            "type": "string",
            "description": "Which source produced the numbers.",
            "enum": [
              "cached",
              "live"
            ]
          }
        },
        "required": [
          "summary",
          "dataMode"
        ]
      },
      "CommissionReport": {
        "type": "object",
        "properties": {
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          },
          "summary": {
            "type": "object",
            "properties": {
              "totalLaborRevenue": {
                "type": "number",
                "description": "Labor revenue attributed to the listed technicians. Dollars as a decimal number (cents divided by 100, not rounded).",
                "x-unit": "dollars"
              },
              "totalCommission": {
                "type": "number",
                "description": "Sum of commission across the listed technicians. Dollars as a decimal number (cents divided by 100, not rounded).",
                "x-unit": "dollars"
              },
              "totalHours": {
                "type": "number",
                "description": "Billed labor hours across the listed technicians.",
                "x-unit": "hours"
              },
              "totalJobs": {
                "type": "integer",
                "description": "Jobs completed across the listed technicians."
              },
              "averageCommissionRate": {
                "type": "number",
                "description": "totalCommission divided by totalLaborRevenue, in percent; 0 when there is no labor revenue.",
                "x-unit": "percent"
              }
            },
            "required": [
              "totalLaborRevenue",
              "totalCommission",
              "totalHours",
              "totalJobs",
              "averageCommissionRate"
            ]
          },
          "mechanics": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "mechanicId": {
                  "type": "string",
                  "description": "Technician (user) id."
                },
                "mechanicName": {
                  "type": "string",
                  "description": "Technician name; Unknown when none was recorded."
                },
                "laborHours": {
                  "type": "number",
                  "description": "Billed labor hours.",
                  "x-unit": "hours"
                },
                "laborRevenue": {
                  "type": "number",
                  "description": "Labor revenue attributed to the technician. Dollars as a decimal number (cents divided by 100, not rounded).",
                  "x-unit": "dollars"
                },
                "jobsCompleted": {
                  "type": "integer",
                  "description": "Jobs completed."
                },
                "commissionRatePercent": {
                  "type": "number",
                  "description": "Most recent non-zero commission rate seen in the range, in percent.",
                  "x-unit": "percent"
                },
                "commission": {
                  "type": "number",
                  "description": "Commission earned. If stored commission is 0 but a rate and labor revenue exist, it is recomputed as revenue times rate. Dollars as a decimal number (cents divided by 100, not rounded).",
                  "x-unit": "dollars"
                }
              },
              "required": [
                "mechanicId",
                "mechanicName",
                "laborHours",
                "laborRevenue",
                "jobsCompleted",
                "commissionRatePercent",
                "commission"
              ]
            },
            "description": "Sorted by commission, highest first."
          }
        },
        "required": [
          "period",
          "summary",
          "mechanics"
        ]
      },
      "CommissionReportResponse": {
        "type": "object",
        "properties": {
          "report": {
            "$ref": "#/components/schemas/CommissionReport"
          },
          "dataMode": {
            "type": "string",
            "description": "Which source produced the numbers.",
            "enum": [
              "cached",
              "live"
            ]
          }
        },
        "required": [
          "report",
          "dataMode"
        ]
      },
      "TaxCategorySplit": {
        "type": "object",
        "properties": {
          "billedCents": {
            "type": "integer",
            "description": "Billed in this category. Integer cents.",
            "x-unit": "cents"
          },
          "receivedCents": {
            "type": "integer",
            "description": "Received (paid) in this category. Integer cents.",
            "x-unit": "cents"
          },
          "taxableBilledCents": {
            "type": "integer",
            "description": "Billed amount that was taxable. Integer cents.",
            "x-unit": "cents"
          },
          "taxableReceivedCents": {
            "type": "integer",
            "description": "Received amount that was taxable. Integer cents.",
            "x-unit": "cents"
          },
          "nonTaxableBilledCents": {
            "type": "integer",
            "description": "Billed amount that was not taxable. Integer cents.",
            "x-unit": "cents"
          },
          "nonTaxableReceivedCents": {
            "type": "integer",
            "description": "Received amount that was not taxable. Integer cents.",
            "x-unit": "cents"
          }
        }
      },
      "TaxCategoryBreakdown": {
        "type": "object",
        "properties": {
          "parts": {
            "$ref": "#/components/schemas/TaxCategorySplit"
          },
          "labor": {
            "$ref": "#/components/schemas/TaxCategorySplit"
          },
          "subcontract": {
            "$ref": "#/components/schemas/TaxCategorySplit"
          },
          "other": {
            "$ref": "#/components/schemas/TaxCategorySplit"
          }
        },
        "description": "Per-category taxable / non-taxable split. `other` is the remainder (fees, shop supplies, EPA, service items) and is always treated as non-taxable. On cash basis the subcontract split is zero (the remainder lands in `other`)."
      },
      "TaxOrderRow": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "description": "Which document type.",
            "enum": [
              "workOrder",
              "salesOrder"
            ]
          },
          "orderNumber": {
            "type": "string",
            "description": "Order / invoice number."
          },
          "customer": {
            "type": "string",
            "description": "Customer name (personal data)."
          },
          "date": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Accrual basis: invoice day. Cash basis: payment day. Shop-local."
          },
          "taxRatePercent": {
            "type": "number",
            "description": "Tax rate in percent (e.g. 8.25).",
            "x-unit": "percent"
          },
          "taxableAmountCents": {
            "type": "integer",
            "description": "Taxable sales on the order. Integer cents.",
            "x-unit": "cents"
          },
          "taxCollectedCents": {
            "type": "integer",
            "description": "Tax billed (accrual) or tax received (cash). Integer cents.",
            "x-unit": "cents"
          },
          "taxBilledCents": {
            "type": "integer",
            "description": "Tax billed. Integer cents.",
            "x-unit": "cents"
          },
          "taxReceivedCents": {
            "type": "integer",
            "description": "Tax received, pro-rated by amount paid. Integer cents.",
            "x-unit": "cents"
          },
          "taxOutstandingCents": {
            "type": "integer",
            "description": "Tax billed but not yet received. Always 0 on cash basis. Integer cents.",
            "x-unit": "cents"
          },
          "partsBilledCents": {
            "type": "integer",
            "description": "Parts billed. Integer cents.",
            "x-unit": "cents"
          },
          "partsReceivedCents": {
            "type": "integer",
            "description": "Parts received. Integer cents.",
            "x-unit": "cents"
          },
          "partsOutstandingCents": {
            "type": "integer",
            "description": "Parts outstanding. Integer cents.",
            "x-unit": "cents"
          },
          "laborBilledCents": {
            "type": "integer",
            "description": "Labor billed. Integer cents.",
            "x-unit": "cents"
          },
          "laborReceivedCents": {
            "type": "integer",
            "description": "Labor received. Integer cents.",
            "x-unit": "cents"
          },
          "laborOutstandingCents": {
            "type": "integer",
            "description": "Labor outstanding. Integer cents.",
            "x-unit": "cents"
          },
          "subcontractBilledCents": {
            "type": "integer",
            "description": "Subcontract billed (accrual only). Integer cents.",
            "x-unit": "cents"
          },
          "subcontractReceivedCents": {
            "type": "integer",
            "description": "Subcontract received (accrual only). Integer cents.",
            "x-unit": "cents"
          },
          "otherBilledCents": {
            "type": "integer",
            "description": "Fees, supplies, EPA and service items billed (accrual only). Integer cents.",
            "x-unit": "cents"
          },
          "otherReceivedCents": {
            "type": "integer",
            "description": "Same, received (accrual only). Integer cents.",
            "x-unit": "cents"
          },
          "partTaxable": {
            "type": "boolean",
            "description": "Whether parts were taxed."
          },
          "laborTaxable": {
            "type": "boolean",
            "description": "Whether labor was taxed."
          },
          "subcontractTaxable": {
            "type": "boolean",
            "description": "Whether subcontract was taxed."
          },
          "isTaxExempt": {
            "type": "boolean",
            "description": "Customer or order was tax exempt."
          },
          "exemptionCategory": {
            "type": "string",
            "description": "Exemption classification.",
            "enum": [
              "repair_labor",
              "resale_crt61",
              "exempt_org",
              "interstate",
              "other_exemption",
              "none"
            ]
          },
          "hasCrt61Doc": {
            "type": "boolean",
            "description": "An exemption certificate document is on file."
          },
          "netSalesCents": {
            "type": "integer",
            "description": "Net sales on the order. Integer cents.",
            "x-unit": "cents"
          },
          "paymentStatus": {
            "type": "string",
            "description": "Payment state. `refunded` occurs on cash basis only (payments in the window net to zero or less).",
            "enum": [
              "paid",
              "partial",
              "unpaid",
              "refunded"
            ]
          },
          "paymentCount": {
            "type": "integer",
            "description": "Cash basis only: number of payment rows netted into this line, refunds included."
          }
        },
        "required": [
          "source",
          "orderNumber",
          "customer",
          "date",
          "taxRatePercent",
          "taxableAmountCents",
          "taxCollectedCents",
          "taxReceivedCents",
          "isTaxExempt",
          "netSalesCents"
        ]
      },
      "TaxRateBucket": {
        "type": "object",
        "properties": {
          "taxRatePercent": {
            "type": "number",
            "description": "Tax rate of this tier, in percent.",
            "x-unit": "percent"
          },
          "taxableAmountCents": {
            "type": "integer",
            "description": "Taxable sales at this rate. Integer cents.",
            "x-unit": "cents"
          },
          "taxCollectedCents": {
            "type": "integer",
            "description": "Tax billed at this rate (cash basis: received). Integer cents.",
            "x-unit": "cents"
          },
          "taxReceivedCents": {
            "type": "integer",
            "description": "Tax received at this rate. Integer cents.",
            "x-unit": "cents"
          },
          "taxOutstandingCents": {
            "type": "integer",
            "description": "Tax billed but not received. Integer cents.",
            "x-unit": "cents"
          },
          "partsBilledCents": {
            "type": "integer",
            "description": "Parts billed. Integer cents.",
            "x-unit": "cents"
          },
          "partsReceivedCents": {
            "type": "integer",
            "description": "Parts received. Integer cents.",
            "x-unit": "cents"
          },
          "laborBilledCents": {
            "type": "integer",
            "description": "Labor billed. Integer cents.",
            "x-unit": "cents"
          },
          "laborReceivedCents": {
            "type": "integer",
            "description": "Labor received. Integer cents.",
            "x-unit": "cents"
          },
          "rateInferred": {
            "type": "boolean",
            "description": "Cash basis only: true when every order in the tier had its rate back-calculated."
          },
          "orderCount": {
            "type": "integer",
            "description": "Orders in the tier (exact)."
          },
          "orders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxOrderRow"
            },
            "description": "Drill-down rows, capped at 250 per tier."
          },
          "ordersTruncated": {
            "type": "boolean",
            "description": "True when the tier has more than 250 orders and `orders` is clipped. Totals are always exact."
          }
        },
        "required": [
          "taxRatePercent",
          "taxableAmountCents",
          "taxCollectedCents",
          "taxReceivedCents",
          "orderCount",
          "orders",
          "ordersTruncated"
        ]
      },
      "TaxNonTaxableBucket": {
        "type": "object",
        "properties": {
          "orderCount": {
            "type": "integer",
            "description": "Orders that carried no tax (exact)."
          },
          "salesCents": {
            "type": "integer",
            "description": "Net sales on those orders. Integer cents.",
            "x-unit": "cents"
          },
          "taxExemptCount": {
            "type": "integer",
            "description": "Of those, orders flagged tax exempt."
          },
          "laborBilledCents": {
            "type": "integer",
            "description": "Labor billed on non-taxable orders. Integer cents.",
            "x-unit": "cents"
          },
          "laborReceivedCents": {
            "type": "integer",
            "description": "Labor received on non-taxable orders. Integer cents.",
            "x-unit": "cents"
          },
          "resaleBilledCents": {
            "type": "integer",
            "description": "Resale-certificate (CRT-61) sales, net of labor. Integer cents.",
            "x-unit": "cents"
          },
          "resaleReceivedCents": {
            "type": "integer",
            "description": "Received portion. Integer cents.",
            "x-unit": "cents"
          },
          "exemptOrgBilledCents": {
            "type": "integer",
            "description": "Exempt-organization sales, net of labor. Integer cents.",
            "x-unit": "cents"
          },
          "exemptOrgReceivedCents": {
            "type": "integer",
            "description": "Received portion. Integer cents.",
            "x-unit": "cents"
          },
          "orders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxOrderRow"
            },
            "description": "Drill-down rows, capped at 250."
          },
          "ordersTruncated": {
            "type": "boolean",
            "description": "True when `orders` is clipped at 250."
          }
        },
        "required": [
          "orderCount",
          "salesCents",
          "taxExemptCount",
          "orders",
          "ordersTruncated"
        ]
      },
      "TaxSummary": {
        "type": "object",
        "properties": {
          "taxableSalesCents": {
            "type": "integer",
            "description": "Taxable sales across all rate tiers. Integer cents.",
            "x-unit": "cents"
          },
          "totalTaxCollectedCents": {
            "type": "integer",
            "description": "Tax billed (accrual) / received (cash). Integer cents.",
            "x-unit": "cents"
          },
          "totalTaxReceivedCents": {
            "type": "integer",
            "description": "Tax actually received. Integer cents.",
            "x-unit": "cents"
          },
          "nonTaxableSalesCents": {
            "type": "integer",
            "description": "Net sales on non-taxable orders. Integer cents.",
            "x-unit": "cents"
          },
          "partsBilledCents": {
            "type": "integer",
            "description": "Parts billed. Integer cents.",
            "x-unit": "cents"
          },
          "partsReceivedCents": {
            "type": "integer",
            "description": "Parts received. Integer cents.",
            "x-unit": "cents"
          },
          "partsOutstandingCents": {
            "type": "integer",
            "description": "Parts outstanding. Integer cents.",
            "x-unit": "cents"
          },
          "laborBilledCents": {
            "type": "integer",
            "description": "Labor billed. Integer cents.",
            "x-unit": "cents"
          },
          "laborReceivedCents": {
            "type": "integer",
            "description": "Labor received. Integer cents.",
            "x-unit": "cents"
          },
          "laborOutstandingCents": {
            "type": "integer",
            "description": "Labor outstanding. Integer cents.",
            "x-unit": "cents"
          },
          "taxBilledCents": {
            "type": "integer",
            "description": "Same as totalTaxCollectedCents. Integer cents.",
            "x-unit": "cents"
          },
          "taxReceivedCents": {
            "type": "integer",
            "description": "Same as totalTaxReceivedCents. Integer cents.",
            "x-unit": "cents"
          },
          "taxOutstandingCents": {
            "type": "integer",
            "description": "Tax billed minus received, floored at 0. Always 0 on cash basis. Integer cents.",
            "x-unit": "cents"
          },
          "effectiveTaxRatePercent": {
            "type": [
              "number",
              "null"
            ],
            "description": "Tax collected divided by taxable sales, in percent rounded to 2 decimals; null when there are no taxable sales.",
            "x-unit": "percent"
          },
          "surchargeReceivedCents": {
            "type": "integer",
            "description": "Cash basis only: card surcharge in the payments received (outside sales and tax). Integer cents.",
            "x-unit": "cents"
          },
          "breakdown": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxRateBucket"
            },
            "description": "One bucket per distinct tax rate, ascending by rate."
          },
          "nonTaxable": {
            "$ref": "#/components/schemas/TaxNonTaxableBucket"
          },
          "categories": {
            "$ref": "#/components/schemas/TaxCategoryBreakdown"
          },
          "ordersTruncated": {
            "type": "boolean",
            "description": "True when any tier or the non-taxable list was clipped at 250 orders."
          }
        },
        "required": [
          "taxableSalesCents",
          "totalTaxCollectedCents",
          "totalTaxReceivedCents",
          "nonTaxableSalesCents",
          "effectiveTaxRatePercent",
          "breakdown",
          "nonTaxable",
          "ordersTruncated"
        ]
      },
      "TaxCollectedResponse": {
        "type": "object",
        "properties": {
          "period": {
            "$ref": "#/components/schemas/ReportPeriod"
          },
          "basis": {
            "type": "string",
            "description": "Accounting basis of the figures.",
            "enum": [
              "accrual",
              "cash"
            ]
          },
          "workOrder": {
            "$ref": "#/components/schemas/TaxSummary"
          },
          "salesOrder": {
            "$ref": "#/components/schemas/TaxSummary"
          },
          "builtOnFirstView": {
            "type": "boolean",
            "description": "True when this request had to rebuild the tax ledger for the range before answering (slower than usual)."
          }
        },
        "required": [
          "period",
          "basis",
          "workOrder",
          "salesOrder",
          "builtOnFirstView"
        ]
      },
      "PartUsageItem": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Part key: the part number, or the description when there is no part number, upper-cased and trimmed."
          },
          "partNumber": {
            "type": "string",
            "description": "Part number; empty string when the part has none."
          },
          "description": {
            "type": "string",
            "description": "Latest description seen."
          },
          "category": {
            "type": "string",
            "description": "Latest category seen; Parts when none."
          },
          "qtyUsed180": {
            "type": "number",
            "description": "Quantity on invoiced work orders dated within the last 180 days, measured from the date of the nightly rebuild (UTC date)."
          },
          "qtyUsedAll": {
            "type": "number",
            "description": "Quantity on all invoiced work orders held in the part-usage ledger."
          },
          "totalCostCents": {
            "type": "integer",
            "description": "Despite its name this is NOT a running total: it is the latest non-zero UNIT cost seen on an invoice (0 if none). Integer cents.",
            "x-unit": "cents"
          },
          "lastUsedDate": {
            "type": "string",
            "description": "Most recent invoice date the part was used (YYYY-MM-DD); empty string when unknown."
          }
        },
        "required": [
          "key",
          "partNumber",
          "description",
          "category",
          "qtyUsed180",
          "qtyUsedAll",
          "totalCostCents",
          "lastUsedDate"
        ]
      },
      "PartUsageResponse": {
        "type": "object",
        "properties": {
          "parts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartUsageItem"
            },
            "description": "Every part with recorded usage, unordered. No cursor and no limit parameter."
          },
          "updatedAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Latest rebuild timestamp across the rows; null when there are no rows.",
            "format": "date-time"
          },
          "count": {
            "type": "integer",
            "description": "Number of parts returned."
          }
        },
        "required": [
          "parts",
          "updatedAt",
          "count"
        ]
      },
      "DigestListItem": {
        "type": "object",
        "properties": {
          "businessDate": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Daily: the shop-local day the digest covers (the completed previous day). Weekly: the Monday of the covered week."
          },
          "period": {
            "type": "string",
            "description": "Cadence.",
            "enum": [
              "daily",
              "weekly"
            ]
          },
          "weekEnd": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Weekly only: the Sunday of the covered week; null for daily."
          },
          "headline": {
            "type": "string",
            "description": "One-line headline (<= 120 chars)."
          },
          "renderMode": {
            "type": "string",
            "description": "`llm` = model-written narrative that passed number validation; `fallback` = deterministic template used instead.",
            "enum": [
              "llm",
              "fallback"
            ]
          },
          "status": {
            "type": "string",
            "description": "Lifecycle state.",
            "enum": [
              "generated",
              "delivered",
              "failed"
            ]
          },
          "feedbackScore": {
            "type": [
              "string",
              "null"
            ],
            "description": "Owner thumbs rating, if given.",
            "enum": [
              "up",
              "down"
            ]
          },
          "createdAt": {
            "type": "string",
            "description": "When the digest row was created.",
            "format": "date-time"
          }
        },
        "required": [
          "businessDate",
          "period",
          "weekEnd",
          "headline",
          "renderMode",
          "status",
          "feedbackScore",
          "createdAt"
        ]
      },
      "DigestListResponse": {
        "type": "object",
        "properties": {
          "digests": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DigestListItem"
            },
            "description": "Newest first."
          }
        },
        "required": [
          "digests"
        ]
      },
      "DigestRecommendedAction": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Action category label."
          },
          "text": {
            "type": "string",
            "description": "Action text (<= 300 chars)."
          },
          "target_id": {
            "type": "string",
            "description": "Optional record id the action points at."
          },
          "route": {
            "type": "string",
            "description": "Optional in-app route."
          },
          "action_type": {
            "type": "string",
            "description": "Optional machine action type."
          },
          "params": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional action parameters."
          }
        },
        "required": [
          "type",
          "text"
        ]
      },
      "DigestNarrative": {
        "type": "object",
        "properties": {
          "headline": {
            "type": "string",
            "description": "Headline, <= 120 chars."
          },
          "summary": {
            "type": "string",
            "description": "Summary paragraph, <= 1200 chars."
          },
          "bullets": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Bullet."
            },
            "description": "1-3 bullets; the collapsed-card view."
          },
          "wins": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Win."
            },
            "description": "Up to 3."
          },
          "concerns": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Concern."
            },
            "description": "Up to 3."
          },
          "watch_items": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Item to watch."
            },
            "description": "Up to 2."
          },
          "recommended_actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DigestRecommendedAction"
            },
            "description": "1-3 actions."
          },
          "callouts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "metric": {
                  "type": "string",
                  "description": "Snapshot metric name."
                },
                "text": {
                  "type": "string",
                  "description": "Callout text, <= 140 chars."
                }
              },
              "required": [
                "metric",
                "text"
              ]
            },
            "description": "Up to 4."
          },
          "shop_pulse": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "description": "Overall read.",
                "enum": [
                  "strong",
                  "steady",
                  "attention"
                ]
              },
              "headline": {
                "type": "string",
                "description": "Pulse headline."
              }
            }
          },
          "money_on_table": {
            "type": "object",
            "properties": {
              "unbilled_wip_display": {
                "type": "string",
                "description": "Pre-formatted dollars, e.g. $4,832.50."
              },
              "open_estimates_display": {
                "type": "string",
                "description": "Pre-formatted dollars."
              },
              "overdue_ar_display": {
                "type": "string",
                "description": "Pre-formatted dollars."
              },
              "total_display": {
                "type": "string",
                "description": "Pre-formatted dollars."
              }
            }
          }
        },
        "required": [
          "headline",
          "summary",
          "bullets",
          "wins",
          "concerns",
          "watch_items",
          "recommended_actions",
          "callouts"
        ],
        "description": "Written narrative. Every number in it is copied from a `display` string in the snapshot; the model never computes figures. The same shape is produced by the fallback template. Text fields contain pre-formatted display strings, not raw cents."
      },
      "DigestMoneyDelta": {
        "type": "object",
        "properties": {
          "cents": {
            "type": "integer",
            "description": "The COMPARISON value (e.g. yesterday's amount), not the difference. Integer cents.",
            "x-unit": "cents"
          },
          "display": {
            "type": "string",
            "description": "Comparison value as text, e.g. $4,832.50."
          },
          "delta_pct": {
            "type": [
              "number",
              "null"
            ],
            "description": "Percent change from the comparison value to the current value, rounded to 0.1; null when the comparison value is 0.",
            "x-unit": "percent"
          },
          "delta_display": {
            "type": "string",
            "description": "Signed percent text such as +23.6%; an em dash when delta_pct is null."
          }
        },
        "required": [
          "cents",
          "display",
          "delta_pct",
          "delta_display"
        ]
      },
      "DigestMoneyBaseline": {
        "type": "object",
        "properties": {
          "cents": {
            "type": "integer",
            "description": "Mean of the trailing points. Integer cents.",
            "x-unit": "cents"
          },
          "display": {
            "type": "string",
            "description": "Mean as text."
          },
          "points": {
            "type": "integer",
            "description": "Number of trailing points averaged (at most 4)."
          }
        },
        "required": [
          "cents",
          "display",
          "points"
        ]
      },
      "DigestMoneySimple": {
        "type": "object",
        "properties": {
          "cents": {
            "type": "integer",
            "description": "Amount. Integer cents.",
            "x-unit": "cents"
          },
          "display": {
            "type": "string",
            "description": "Amount as text, e.g. $4,832.50."
          }
        },
        "required": [
          "cents",
          "display"
        ]
      },
      "DigestMoneyMetric": {
        "type": "object",
        "properties": {
          "cents": {
            "type": "integer",
            "description": "Current-period amount. Integer cents.",
            "x-unit": "cents"
          },
          "display": {
            "type": "string",
            "description": "Amount as text."
          },
          "vs_yesterday": {
            "$ref": "#/components/schemas/DigestMoneyDelta"
          },
          "vs_same_weekday_last_week": {
            "$ref": "#/components/schemas/DigestMoneyDelta"
          },
          "trailing_4wk_same_weekday_avg": {
            "$ref": "#/components/schemas/DigestMoneyBaseline"
          },
          "vs_prior_week": {
            "$ref": "#/components/schemas/DigestMoneyDelta"
          },
          "trailing_4wk_avg": {
            "$ref": "#/components/schemas/DigestMoneyBaseline"
          }
        },
        "required": [
          "cents",
          "display"
        ],
        "description": "Money metric with comparisons. Daily digests carry vs_yesterday / vs_same_weekday_last_week / trailing_4wk_same_weekday_avg; weekly digests carry vs_prior_week / trailing_4wk_avg. Comparisons are omitted while the shop has less than 14 days of history (welcome_mode)."
      },
      "DigestCountDelta": {
        "type": "object",
        "properties": {
          "value": {
            "type": "number",
            "description": "The COMPARISON count."
          },
          "display": {
            "type": "string",
            "description": "Comparison count as text."
          },
          "delta_pct": {
            "type": [
              "number",
              "null"
            ],
            "description": "Percent change, rounded to 0.1; null when the comparison is 0.",
            "x-unit": "percent"
          },
          "delta_display": {
            "type": "string",
            "description": "Signed percent text."
          }
        },
        "required": [
          "value",
          "display",
          "delta_pct",
          "delta_display"
        ]
      },
      "DigestCountMetric": {
        "type": "object",
        "properties": {
          "value": {
            "type": "number",
            "description": "Current count."
          },
          "display": {
            "type": "string",
            "description": "Count as text."
          },
          "vs_yesterday": {
            "$ref": "#/components/schemas/DigestCountDelta"
          },
          "vs_same_weekday_last_week": {
            "$ref": "#/components/schemas/DigestCountDelta"
          },
          "trailing_4wk_same_weekday_avg": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Mean count."
              },
              "display": {
                "type": "string",
                "description": "Mean as text."
              },
              "points": {
                "type": "integer",
                "description": "Points averaged."
              }
            }
          },
          "vs_prior_week": {
            "$ref": "#/components/schemas/DigestCountDelta"
          },
          "trailing_4wk_avg": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Mean count."
              },
              "display": {
                "type": "string",
                "description": "Mean as text."
              },
              "points": {
                "type": "integer",
                "description": "Points averaged."
              }
            }
          }
        },
        "required": [
          "value",
          "display"
        ]
      },
      "DigestGrossProfitMetric": {
        "type": "object",
        "properties": {
          "available": {
            "type": "boolean",
            "description": "False when the day's aggregate row predates cost tracking (or is absent); gross profit is then reported unavailable, never estimated."
          },
          "cents": {
            "type": "integer",
            "description": "Gross profit. Integer cents.",
            "x-unit": "cents"
          },
          "display": {
            "type": "string",
            "description": "Gross profit as text."
          },
          "pct": {
            "type": [
              "number",
              "null"
            ],
            "description": "Gross profit as percent of revenue, rounded to 0.1; null when revenue is 0.",
            "x-unit": "percent"
          },
          "pct_display": {
            "type": "string",
            "description": "Percent as text."
          },
          "vs_yesterday": {
            "$ref": "#/components/schemas/DigestMoneyDelta"
          },
          "vs_same_weekday_last_week": {
            "$ref": "#/components/schemas/DigestMoneyDelta"
          },
          "vs_prior_week": {
            "$ref": "#/components/schemas/DigestMoneyDelta"
          }
        },
        "required": [
          "available"
        ]
      },
      "DigestSpanComparison": {
        "type": "object",
        "properties": {
          "current": {
            "type": "object",
            "properties": {
              "cents": {
                "type": "integer",
                "description": "Amount. Integer cents.",
                "x-unit": "cents"
              },
              "display": {
                "type": "string",
                "description": "Text."
              },
              "start": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Span start."
              },
              "end": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Span end."
              }
            }
          },
          "prior": {
            "type": "object",
            "properties": {
              "cents": {
                "type": "integer",
                "description": "Amount. Integer cents.",
                "x-unit": "cents"
              },
              "display": {
                "type": "string",
                "description": "Text."
              },
              "start": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Span start."
              },
              "end": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Span end."
              }
            }
          },
          "delta_pct": {
            "type": [
              "number",
              "null"
            ],
            "description": "Percent change.",
            "x-unit": "percent"
          },
          "delta_display": {
            "type": "string",
            "description": "Signed percent text."
          }
        },
        "description": "Week-to-date versus the same span of the prior week."
      },
      "DigestCountCents": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Count."
          },
          "cents": {
            "type": "integer",
            "description": "Value. Integer cents.",
            "x-unit": "cents"
          },
          "display": {
            "type": "string",
            "description": "Value as text."
          }
        },
        "required": [
          "count",
          "cents",
          "display"
        ]
      },
      "DigestAnomaly": {
        "type": "object",
        "properties": {
          "metric": {
            "type": "string",
            "description": "Metric name."
          },
          "severity": {
            "type": "string",
            "description": "Severity.",
            "enum": [
              "info",
              "warn"
            ]
          },
          "direction": {
            "type": "string",
            "description": "Direction of the move.",
            "enum": [
              "up",
              "down"
            ]
          },
          "rule": {
            "type": "string",
            "description": "Rule that fired."
          },
          "context": {
            "type": "string",
            "description": "Plain-language context using snapshot display strings."
          }
        },
        "required": [
          "metric",
          "severity",
          "direction",
          "rule",
          "context"
        ]
      },
      "DigestSnapshot": {
        "type": "object",
        "properties": {
          "schema_version": {
            "type": "integer",
            "description": "Snapshot schema version (currently 1)."
          },
          "period": {
            "type": "string",
            "description": "Cadence. Absent on rows written before the weekly digest existed (treat as daily).",
            "enum": [
              "daily",
              "weekly"
            ]
          },
          "tenant": {
            "type": "object",
            "properties": {
              "shop_name": {
                "type": "string",
                "description": "Shop name."
              },
              "timezone": {
                "type": "string",
                "description": "IANA time zone the digest was built in."
              },
              "currency": {
                "type": "string",
                "description": "Always USD.",
                "enum": [
                  "USD"
                ]
              }
            },
            "required": [
              "shop_name",
              "timezone",
              "currency"
            ]
          },
          "business_date": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Daily: covered day. Weekly: the week's Monday."
          },
          "day_of_week": {
            "type": "string",
            "description": "Weekday name of business_date."
          },
          "week": {
            "type": "object",
            "properties": {
              "start": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Monday."
              },
              "end": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Sunday."
              }
            },
            "description": "Weekly only: covered span."
          },
          "week_days": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date",
                  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                  "description": "Day."
                },
                "day_of_week": {
                  "type": "string",
                  "description": "Weekday name."
                },
                "cents": {
                  "type": "integer",
                  "description": "Revenue that day. Integer cents.",
                  "x-unit": "cents"
                },
                "display": {
                  "type": "string",
                  "description": "Revenue as text."
                }
              }
            },
            "description": "Weekly only: per-day revenue."
          },
          "history_days": {
            "type": "integer",
            "description": "Days of aggregate history available to the shop."
          },
          "welcome_mode": {
            "type": "boolean",
            "description": "True when history is shorter than 14 days; all comparisons and anomalies are suppressed."
          },
          "metrics": {
            "type": "object",
            "properties": {
              "total_revenue": {
                "$ref": "#/components/schemas/DigestMoneyMetric"
              },
              "labor_revenue": {
                "$ref": "#/components/schemas/DigestMoneyMetric"
              },
              "parts_revenue": {
                "$ref": "#/components/schemas/DigestMoneyMetric"
              },
              "payments_collected": {
                "$ref": "#/components/schemas/DigestMoneyMetric"
              },
              "average_ro": {
                "$ref": "#/components/schemas/DigestMoneyMetric"
              },
              "unit_count": {
                "$ref": "#/components/schemas/DigestCountMetric"
              },
              "gross_profit": {
                "$ref": "#/components/schemas/DigestGrossProfitMetric"
              },
              "tires_revenue": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "fees": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "epa": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "shop_supplies": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "service_items": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "subcontracts": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "discounts": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "counter_sales": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "wtd_vs_prior_wtd": {
                "$ref": "#/components/schemas/DigestSpanComparison"
              },
              "estimates_created": {
                "$ref": "#/components/schemas/DigestCountCents"
              },
              "open_estimate_pipeline": {
                "$ref": "#/components/schemas/DigestCountCents"
              },
              "declined_work_mtd": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "open_wip": {
                "$ref": "#/components/schemas/DigestCountCents"
              },
              "aging_wip": {
                "type": "object",
                "properties": {
                  "count": {
                    "type": "integer",
                    "description": "Orders open longer than business_days business days."
                  },
                  "cents": {
                    "type": "integer",
                    "description": "Value. Integer cents.",
                    "x-unit": "cents"
                  },
                  "display": {
                    "type": "string",
                    "description": "Value as text."
                  },
                  "oldest_days": {
                    "type": "integer",
                    "description": "Age of the oldest, in days."
                  },
                  "business_days": {
                    "type": "integer",
                    "description": "Aging threshold in business days (3)."
                  }
                }
              },
              "ar_outstanding": {
                "$ref": "#/components/schemas/DigestMoneySimple"
              },
              "ar_over_30": {
                "type": "object",
                "properties": {
                  "cents": {
                    "type": "integer",
                    "description": "Receivables more than 30 days old. Integer cents.",
                    "x-unit": "cents"
                  },
                  "display": {
                    "type": "string",
                    "description": "Text."
                  },
                  "vs_yesterday": {
                    "$ref": "#/components/schemas/DigestMoneyDelta"
                  },
                  "vs_prior_week": {
                    "$ref": "#/components/schemas/DigestMoneyDelta"
                  }
                }
              }
            },
            "required": [
              "total_revenue",
              "labor_revenue",
              "parts_revenue",
              "payments_collected",
              "average_ro",
              "unit_count",
              "gross_profit"
            ],
            "description": "Headline metrics. Sections after counter_sales are optional and omitted when the source was off or unreadable. All money is cents with a matching display string."
          },
          "top_jobs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "wo": {
                  "type": "string",
                  "description": "Work-order number."
                },
                "customer": {
                  "type": "string",
                  "description": "Customer name; omitted when the shop redacts customer names."
                },
                "cents": {
                  "type": "integer",
                  "description": "Job value. Integer cents.",
                  "x-unit": "cents"
                },
                "display": {
                  "type": "string",
                  "description": "Text."
                }
              },
              "required": [
                "wo",
                "cents",
                "display"
              ]
            }
          },
          "aging_wip_list": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "wo": {
                  "type": "string",
                  "description": "Work-order number."
                },
                "wo_id": {
                  "type": "string",
                  "description": "Work-order id (absent on snapshots before 2026-09-27)."
                },
                "days_open": {
                  "type": "integer",
                  "description": "Days open."
                },
                "cents": {
                  "type": "integer",
                  "description": "Value. Integer cents.",
                  "x-unit": "cents"
                },
                "display": {
                  "type": "string",
                  "description": "Text."
                }
              },
              "required": [
                "wo",
                "days_open",
                "cents",
                "display"
              ]
            }
          },
          "anomalies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DigestAnomaly"
            }
          },
          "shop_pulse": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "description": "Overall read.",
                "enum": [
                  "strong",
                  "steady",
                  "attention"
                ]
              },
              "headline": {
                "type": "string",
                "description": "Headline."
              }
            }
          },
          "money_on_table": {
            "type": "object",
            "properties": {
              "unbilled_wip_cents": {
                "type": "integer",
                "description": "Open work not yet invoiced. Integer cents.",
                "x-unit": "cents"
              },
              "open_estimates_cents": {
                "type": "integer",
                "description": "Open estimate pipeline. Integer cents.",
                "x-unit": "cents"
              },
              "overdue_ar_cents": {
                "type": "integer",
                "description": "Overdue receivables. Integer cents.",
                "x-unit": "cents"
              },
              "total_cents": {
                "type": "integer",
                "description": "Sum of the three. Integer cents.",
                "x-unit": "cents"
              },
              "unbilled_wip_display": {
                "type": "string",
                "description": "Text."
              },
              "open_estimates_display": {
                "type": "string",
                "description": "Text."
              },
              "overdue_ar_display": {
                "type": "string",
                "description": "Text."
              },
              "total_display": {
                "type": "string",
                "description": "Text."
              }
            }
          },
          "parts_summary": {
            "type": "object",
            "properties": {
              "purchased_cents": {
                "type": "integer",
                "description": "Purchased from vendors. Integer cents.",
                "x-unit": "cents"
              },
              "stock_added_cents": {
                "type": "integer",
                "description": "Stock added. Integer cents.",
                "x-unit": "cents"
              },
              "total_inbound_cents": {
                "type": "integer",
                "description": "Total inbound. Integer cents.",
                "x-unit": "cents"
              },
              "net_purchases_cents": {
                "type": "integer",
                "description": "Inbound net of vendor returns. Integer cents.",
                "x-unit": "cents"
              },
              "consumed_cost_cents": {
                "type": "integer",
                "description": "Cost of parts consumed. Integer cents.",
                "x-unit": "cents"
              },
              "consumed_revenue_cents": {
                "type": "integer",
                "description": "Revenue on consumed parts. Integer cents.",
                "x-unit": "cents"
              },
              "reserved_delta_cents": {
                "type": "integer",
                "description": "Change in reserved stock value. Integer cents.",
                "x-unit": "cents"
              },
              "inbound_quantity": {
                "type": "number",
                "description": "Units inbound."
              },
              "consumed_quantity": {
                "type": "number",
                "description": "Units consumed."
              },
              "top_vendors": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "vendor": {
                      "type": "string",
                      "description": "Vendor."
                    },
                    "cents": {
                      "type": "integer",
                      "description": "Spend. Integer cents.",
                      "x-unit": "cents"
                    },
                    "display": {
                      "type": "string",
                      "description": "Text."
                    }
                  }
                }
              },
              "top_parts": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "Part name."
                    },
                    "part_number": {
                      "type": "string",
                      "description": "Part number."
                    },
                    "quantity": {
                      "type": "number",
                      "description": "Units."
                    },
                    "cents": {
                      "type": "integer",
                      "description": "Value. Integer cents.",
                      "x-unit": "cents"
                    },
                    "display": {
                      "type": "string",
                      "description": "Text."
                    }
                  }
                }
              }
            },
            "description": "Each *_cents field also has a matching *_display text field (omitted here for brevity)."
          },
          "maintenance_due": {
            "type": "object",
            "properties": {
              "overdue_count": {
                "type": "integer",
                "description": "Overdue services."
              },
              "due_soon_count": {
                "type": "integer",
                "description": "Services due soon."
              },
              "lead_days": {
                "type": "integer",
                "description": "Shop's reminder lead in days."
              },
              "lead_miles": {
                "type": "integer",
                "description": "Shop's reminder lead in miles."
              },
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "vehicle": {
                      "type": "string",
                      "description": "Vehicle label."
                    },
                    "vehicle_id": {
                      "type": "string",
                      "description": "Vehicle id."
                    },
                    "service": {
                      "type": "string",
                      "description": "Service name."
                    },
                    "status": {
                      "type": "string",
                      "description": "Urgency.",
                      "enum": [
                        "overdue",
                        "due_soon"
                      ]
                    },
                    "detail": {
                      "type": "string",
                      "description": "Where it stands, e.g. 1,200 mi left, 5d left."
                    },
                    "due_by_date": {
                      "type": "string",
                      "format": "date",
                      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                      "description": "Due date, if date-based."
                    }
                  }
                },
                "description": "Most urgent first, capped."
              },
              "more_count": {
                "type": "integer",
                "description": "Items not listed because of the cap."
              }
            },
            "description": "Daily digest only; present when the shop includes the maintenance section."
          }
        },
        "required": [
          "schema_version",
          "tenant",
          "business_date",
          "day_of_week",
          "history_days",
          "welcome_mode",
          "metrics",
          "anomalies"
        ],
        "description": "The immutable data record the digest was built from. Keys are snake_case. Cents are canonical; every money value carries a `display` string. Percent deltas are precomputed."
      },
      "DigestDetail": {
        "type": "object",
        "properties": {
          "businessDate": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Daily: the shop-local day the digest covers (the completed previous day). Weekly: the Monday of the covered week."
          },
          "period": {
            "type": "string",
            "description": "Cadence.",
            "enum": [
              "daily",
              "weekly"
            ]
          },
          "weekEnd": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Weekly only: the Sunday of the covered week; null for daily."
          },
          "headline": {
            "type": "string",
            "description": "One-line headline (<= 120 chars)."
          },
          "renderMode": {
            "type": "string",
            "description": "`llm` = model-written narrative that passed number validation; `fallback` = deterministic template used instead.",
            "enum": [
              "llm",
              "fallback"
            ]
          },
          "status": {
            "type": "string",
            "description": "Lifecycle state.",
            "enum": [
              "generated",
              "delivered",
              "failed"
            ]
          },
          "feedbackScore": {
            "type": [
              "string",
              "null"
            ],
            "description": "Owner thumbs rating, if given.",
            "enum": [
              "up",
              "down"
            ]
          },
          "createdAt": {
            "type": "string",
            "description": "When the digest row was created.",
            "format": "date-time"
          },
          "narrative": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DigestNarrative"
              },
              {
                "type": "null"
              }
            ],
            "description": "Parsed narrative; null if the stored JSON could not be parsed."
          },
          "snapshot": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DigestSnapshot"
              },
              {
                "type": "null"
              }
            ],
            "description": "Parsed snapshot; null if the stored JSON could not be parsed."
          },
          "feedbackComment": {
            "type": [
              "string",
              "null"
            ],
            "description": "Owner's feedback comment, if any."
          },
          "deliveredAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "When the digest was delivered in-app.",
            "format": "date-time"
          },
          "emailedAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "When the digest email was sent.",
            "format": "date-time"
          }
        },
        "required": [
          "businessDate",
          "period",
          "weekEnd",
          "headline",
          "renderMode",
          "status",
          "feedbackScore",
          "createdAt",
          "narrative",
          "snapshot",
          "feedbackComment",
          "deliveredAt",
          "emailedAt"
        ],
        "description": "Full digest: list fields plus the narrative and the snapshot it was built from. Model, token and cost fields are deliberately not exposed."
      },
      "DashboardTrendPoint": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Shop-local day."
          },
          "invoiceCount": {
            "type": "integer",
            "description": "Invoices that day."
          },
          "totalRevenue": {
            "type": "number",
            "description": "Invoice grand total. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "laborRevenue": {
            "type": "number",
            "description": "Labor revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "partsRevenue": {
            "type": "number",
            "description": "Parts revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "tiresRevenue": {
            "type": "number",
            "description": "Tire revenue. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "paidInvoiceCount": {
            "type": "integer",
            "description": "Fully paid invoices."
          },
          "paidTotalRevenue": {
            "type": "number",
            "description": "Grand total of fully paid invoices. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "paidLaborRevenue": {
            "type": "number",
            "description": "Labor revenue on fully paid invoices. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "paidPartsRevenue": {
            "type": "number",
            "description": "Parts revenue on fully paid invoices. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "salesOrderRevenue": {
            "type": "number",
            "description": "Counter-sale revenue (a subset of totalRevenue). Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "paidSalesOrderRevenue": {
            "type": "number",
            "description": "Counter-sale revenue on paid sales orders (subset of paidTotalRevenue). Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "paymentTotal": {
            "type": "number",
            "description": "Payments received that day. Dollars as a decimal number (cents divided by 100, not rounded).",
            "x-unit": "dollars"
          },
          "paymentCount": {
            "type": "integer",
            "description": "Payment transactions that day."
          },
          "uniqueCustomerCount": {
            "type": "integer",
            "description": "Distinct customers that day."
          },
          "technicianStats": {
            "type": "object",
            "properties": {},
            "description": "Per-technician stats keyed by technician id. UNLIKE the fields above, money inside here is still in integer CENTS (laborRevenueCents, commissionCents).",
            "additionalProperties": {
              "$ref": "#/components/schemas/TechnicianDailyStats"
            }
          }
        },
        "required": [
          "date",
          "invoiceCount",
          "totalRevenue",
          "paymentTotal",
          "technicianStats"
        ]
      },
      "DashboardTrendAggregatesResponse": {
        "type": "object",
        "properties": {
          "trendData": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DashboardTrendPoint"
            },
            "description": "One entry per day that has a stored row, ascending. Days with no stored row are omitted."
          },
          "startDate": {
            "type": "string",
            "description": "Echo of the startDate parameter."
          },
          "endDate": {
            "type": "string",
            "description": "Echo of the endDate parameter."
          },
          "daysWithData": {
            "type": "integer",
            "description": "Entries with at least one invoice or payment."
          }
        },
        "required": [
          "trendData",
          "startDate",
          "endDate",
          "daysWithData"
        ]
      },
      "DashboardStampedValue": {
        "type": "object",
        "properties": {
          "value": {
            "type": "number",
            "description": "The figure."
          },
          "updatedAt": {
            "type": "string",
            "description": "The time of THIS REQUEST, not of the underlying data. Use `freshness` for data age.",
            "format": "date-time"
          }
        },
        "required": [
          "value",
          "updatedAt"
        ]
      },
      "DashboardGrossProfit": {
        "type": "object",
        "properties": {
          "value": {
            "type": "number",
            "description": "Gross profit for the range: revenue minus cost of sales (work orders plus counter sales). Treat as unknown when costsKnown is false. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "revenue": {
            "type": "number",
            "description": "Revenue the profit is measured against: work-order revenue plus counter-sale revenue, both NET OF SALES TAX. This is lower than periodRevenue, which includes tax. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "partsCost": {
            "type": "number",
            "description": "Work-order cost of parts, tires, materials and subcontracts combined. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "laborCost": {
            "type": "number",
            "description": "Work-order labor cost. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "counterRevenue": {
            "type": "number",
            "description": "Counter-sale revenue net of tax. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "counterCost": {
            "type": "number",
            "description": "Counter-sale cost of goods; 0 when counter-sale cost is not known for the range. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "grossMarginPct": {
            "type": "number",
            "description": "value divided by revenue, rounded to a whole percent; 0 when revenue is 0.",
            "x-unit": "percent"
          },
          "costsKnown": {
            "type": "boolean",
            "description": "False when the stored rows cannot support a profit figure (a row predates cost tracking, no rows exist, or no cost was recorded). The UI shows a dash; do not trust `value` then."
          },
          "laborCostKnown": {
            "type": "boolean",
            "description": "False when labor cost could not be established for the range."
          }
        },
        "required": [
          "value",
          "revenue",
          "partsCost",
          "laborCost",
          "counterRevenue",
          "counterCost",
          "grossMarginPct",
          "costsKnown",
          "laborCostKnown"
        ]
      },
      "DashboardTechUtilization": {
        "type": "object",
        "properties": {
          "billedHours": {
            "type": "number",
            "description": "Billed labor hours in the range (all labor lines, attributed or not, declined work excluded), rounded to 0.1.",
            "x-unit": "hours"
          },
          "availableHours": {
            "type": "number",
            "description": "Capacity: 8 hours x days in the range x technician count.",
            "x-unit": "hours"
          },
          "utilizationPct": {
            "type": "number",
            "description": "billedHours / availableHours, whole percent, capped at 100.",
            "x-unit": "percent"
          },
          "idlePct": {
            "type": "number",
            "description": "100 minus utilizationPct.",
            "x-unit": "percent"
          },
          "techCount": {
            "type": "integer",
            "description": "Technicians seen in the range's stored technician stats; at least 1."
          },
          "effectiveLaborRate": {
            "type": "number",
            "description": "Labor revenue divided by billed hours (dollars per hour); 0 when no hours. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "hasData": {
            "type": "boolean",
            "description": "False when there are no billed hours, or the stored rows cannot support the figure (then every other field is zero and idlePct is 100)."
          }
        },
        "required": [
          "billedHours",
          "availableHours",
          "utilizationPct",
          "idlePct",
          "techCount",
          "effectiveLaborRate",
          "hasData"
        ]
      },
      "DashboardTrendDay": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Shop-local day."
          },
          "invoicedCents": {
            "type": "integer",
            "description": "Work-order invoiced revenue that day, tax included, counter sales EXCLUDED. Integer cents.",
            "x-unit": "cents"
          },
          "invoicedCount": {
            "type": "integer",
            "description": "Invoice count that day. Includes counter sales, unlike invoicedCents."
          },
          "customers": {
            "type": "integer",
            "description": "Distinct customers that day."
          },
          "salesOrderInvoicedCents": {
            "type": "integer",
            "description": "Counter-sale revenue that day. Integer cents.",
            "x-unit": "cents"
          },
          "paymentCents": {
            "type": "integer",
            "description": "Cash received that day, net of refunds, all document types. Integer cents.",
            "x-unit": "cents"
          },
          "paymentCount": {
            "type": "integer",
            "description": "Payment transactions that day."
          },
          "paidInvoiceCount": {
            "type": "integer",
            "description": "Fully paid invoices dated that day."
          },
          "laborHours": {
            "type": "number",
            "description": "Billed labor hours, rounded to 0.1.",
            "x-unit": "hours"
          },
          "laborRevenueCents": {
            "type": "integer",
            "description": "Labor revenue. Integer cents.",
            "x-unit": "cents"
          },
          "partsRevenueCents": {
            "type": "integer",
            "description": "Parts plus tire revenue. Integer cents.",
            "x-unit": "cents"
          },
          "paidLaborRevenueCents": {
            "type": "integer",
            "description": "Labor revenue on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          },
          "paidPartsRevenueCents": {
            "type": "integer",
            "description": "Parts plus tire revenue on fully paid invoices. Integer cents.",
            "x-unit": "cents"
          }
        },
        "required": [
          "date",
          "invoicedCents",
          "invoicedCount",
          "customers",
          "salesOrderInvoicedCents",
          "paymentCents",
          "paymentCount",
          "paidInvoiceCount",
          "laborHours",
          "laborRevenueCents",
          "partsRevenueCents",
          "paidLaborRevenueCents",
          "paidPartsRevenueCents"
        ]
      },
      "DashboardFloorSample": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Work-order id."
          },
          "orderNumber": {
            "type": "string",
            "description": "Work-order number."
          },
          "customerName": {
            "type": "string",
            "description": "Customer name (personal data)."
          },
          "days": {
            "type": "integer",
            "description": "Days late (delayed) or days idle (stale); absent for waiting-for-parts samples."
          }
        },
        "required": [
          "id",
          "orderNumber"
        ]
      },
      "DashboardFloor": {
        "type": "object",
        "properties": {
          "delayedWorkOrders": {
            "type": "integer",
            "description": "Open work orders more than 3 days past their due date."
          },
          "staleWorkOrders": {
            "type": "integer",
            "description": "Open work orders with no write in 7 days or more."
          },
          "waitingForPartsWorkOrders": {
            "type": "integer",
            "description": "Open work orders whose status contains waiting, parts or on hold."
          },
          "samples": {
            "type": "object",
            "properties": {
              "delayed": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DashboardFloorSample"
                },
                "description": "Up to 3, most days late first."
              },
              "waitingForParts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DashboardFloorSample"
                },
                "description": "Up to 3."
              },
              "stale": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DashboardFloorSample"
                },
                "description": "Up to 3, most idle first."
              }
            },
            "required": [
              "delayed",
              "waitingForParts",
              "stale"
            ]
          },
          "recountedAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "When the hourly recount last ran for this shop.",
            "format": "date-time"
          }
        },
        "required": [
          "delayedWorkOrders",
          "staleWorkOrders",
          "waitingForPartsWorkOrders",
          "samples",
          "recountedAt"
        ],
        "description": "Clock-derived floor counters. null on the parent when the shop has no dashboard state row yet."
      },
      "DashboardPaymentHealth": {
        "type": "object",
        "properties": {
          "collectionRate": {
            "type": "number",
            "description": "Paid divided by invoiced across ALL realized invoices ever, whole percent.",
            "x-unit": "percent"
          },
          "avgDaysToPay": {
            "type": "number",
            "description": "Mean days from invoice to payment over fully paid invoices, rounded to a whole day.",
            "x-unit": "days"
          },
          "overdueRevenuePct": {
            "type": "number",
            "description": "Unpaid balance divided by invoiced, whole percent. 'Overdue' here means any unpaid balance, not only past-due-date.",
            "x-unit": "percent"
          },
          "totalInvoiced": {
            "type": "number",
            "description": "Sum invoiced across all realized invoices ever. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "totalPaid": {
            "type": "number",
            "description": "Sum paid. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "totalOverdue": {
            "type": "number",
            "description": "Sum of unpaid balances. Dollars as a decimal number.",
            "x-unit": "dollars"
          },
          "hasData": {
            "type": "boolean",
            "description": "False when there are no realized invoices (or no AR snapshot yet); the other fields are then 0."
          }
        },
        "required": [
          "collectionRate",
          "avgDaysToPay",
          "overdueRevenuePct",
          "totalInvoiced",
          "totalPaid",
          "totalOverdue",
          "hasData"
        ]
      },
      "DashboardCollections": {
        "type": "object",
        "properties": {
          "byCustomer": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "customerId": {
                  "type": "string",
                  "description": "Customer id (or the customer name when the invoice had no id)."
                },
                "name": {
                  "type": "string",
                  "description": "Customer name (personal data)."
                },
                "totalDue": {
                  "type": "number",
                  "description": "Unpaid balance across the customer's invoices. Dollars as a decimal number.",
                  "x-unit": "dollars"
                },
                "invoiceCount": {
                  "type": "integer",
                  "description": "Unpaid invoices."
                }
              },
              "required": [
                "customerId",
                "name",
                "totalDue",
                "invoiceCount"
              ]
            },
            "description": "Top 5 customers by amount due. Capped with no truncated flag."
          },
          "byInvoice": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Work-order id."
                },
                "orderNumber": {
                  "type": "string",
                  "description": "Invoice / order number."
                },
                "customerName": {
                  "type": "string",
                  "description": "Customer name (personal data)."
                },
                "customerId": {
                  "type": "string",
                  "description": "Customer id."
                },
                "vehicleInfo": {
                  "type": "string",
                  "description": "Vehicle label."
                },
                "total": {
                  "type": "number",
                  "description": "Invoice total. Dollars as a decimal number.",
                  "x-unit": "dollars"
                },
                "paid": {
                  "type": "number",
                  "description": "Paid so far. Dollars as a decimal number.",
                  "x-unit": "dollars"
                },
                "due": {
                  "type": "number",
                  "description": "Balance due. Dollars as a decimal number.",
                  "x-unit": "dollars"
                }
              },
              "required": [
                "id",
                "orderNumber",
                "customerName",
                "vehicleInfo",
                "total",
                "paid",
                "due"
              ]
            },
            "description": "Top 10 invoices by balance due. Capped with no truncated flag."
          },
          "hasData": {
            "type": "boolean",
            "description": "False when nothing is owed (or no AR snapshot yet)."
          }
        },
        "required": [
          "byCustomer",
          "byInvoice",
          "hasData"
        ],
        "description": "All-time outstanding receivables from last night's AR aging snapshot; not scoped to the date range."
      },
      "DashboardMetrics": {
        "type": "object",
        "properties": {
          "periodRevenue": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Invoiced revenue in the range: work orders plus counter sales, SALES TAX INCLUDED, card surcharge excluded. Dollars as a decimal number.",
                "x-unit": "dollars"
              }
            },
            "required": [
              "value"
            ]
          },
          "monthlyRevenue": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Same number as periodRevenue (legacy alias, whatever the range length). Dollars as a decimal number.",
                "x-unit": "dollars"
              },
              "trend": {
                "type": "number",
                "description": "Always 0 (legacy)."
              }
            },
            "required": [
              "value",
              "trend"
            ]
          },
          "periodCompleted": {
            "type": "object",
            "properties": {
              "value": {
                "type": "integer",
                "description": "Invoices dated in the range (work orders plus counter sales)."
              }
            },
            "required": [
              "value"
            ]
          },
          "avgPerJob": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "periodRevenue divided by periodCompleted (tax included), rounded to cents; 0 when no invoices. Dollars as a decimal number.",
                "x-unit": "dollars"
              }
            },
            "required": [
              "value"
            ]
          },
          "revenuePctChange": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Percent change of periodRevenue versus the previous period, whole percent, clamped to -999..999. When the previous period is 0 it is 100 if the current period has revenue, else 0.",
                "x-unit": "percent"
              }
            },
            "required": [
              "value"
            ]
          },
          "prevPeriodRevenue": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "periodRevenue for the previous period: the same number of days immediately before startDate. Dollars as a decimal number.",
                "x-unit": "dollars"
              }
            },
            "required": [
              "value"
            ]
          },
          "prevPeriodCompleted": {
            "type": "object",
            "properties": {
              "value": {
                "type": "integer",
                "description": "Invoice count for the previous period."
              }
            },
            "required": [
              "value"
            ]
          },
          "counterRevenue": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Counter-sale share of periodRevenue (tax included). Dollars as a decimal number.",
                "x-unit": "dollars"
              }
            },
            "required": [
              "value"
            ]
          },
          "paymentsReceived": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Cash received in the range, net of refunds and voids, counter sales included. Dollars as a decimal number.",
                "x-unit": "dollars"
              }
            },
            "required": [
              "value"
            ]
          },
          "cashCollected": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Same number as paymentsReceived (legacy alias). Dollars as a decimal number.",
                "x-unit": "dollars"
              }
            },
            "required": [
              "value"
            ]
          },
          "grossProfit": {
            "$ref": "#/components/schemas/DashboardGrossProfit"
          },
          "prevPeriodGrossProfit": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Gross profit for the previous period on the same basis as grossProfit. Dollars as a decimal number.",
                "x-unit": "dollars"
              },
              "costsKnown": {
                "type": "boolean",
                "description": "False when the previous period's rows cannot support a profit figure."
              }
            },
            "required": [
              "value",
              "costsKnown"
            ]
          },
          "techUtilization": {
            "$ref": "#/components/schemas/DashboardTechUtilization"
          },
          "trendDaily": {
            "type": "object",
            "properties": {
              "days": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DashboardTrendDay"
                },
                "description": "One entry per day of the range, zero-filled, ascending. Money here is CENTS."
              },
              "startDate": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Range start used."
              },
              "endDate": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Range end used."
              },
              "timezone": {
                "type": "string",
                "description": "Echo of the timezone parameter (or the America/Chicago default)."
              }
            },
            "required": [
              "days",
              "startDate",
              "endDate",
              "timezone"
            ]
          },
          "customersServed": {
            "type": "object",
            "properties": {
              "value": {
                "type": "integer",
                "description": "Distinct customers in the range. If per-day customer id lists are missing from the stored rows it degrades to a sum of daily counts, so a customer seen on two days can count twice."
              }
            },
            "required": [
              "value"
            ]
          },
          "vehiclesServed": {
            "type": "object",
            "properties": {
              "value": {
                "type": "integer",
                "description": "Distinct vehicles in the range."
              }
            },
            "required": [
              "value"
            ]
          },
          "activeWorkOrders": {
            "$ref": "#/components/schemas/DashboardStampedValue",
            "description": "Open work on the floor right now (not estimates, not invoiced, not archived or deleted). Count."
          },
          "vehiclesInShop": {
            "$ref": "#/components/schemas/DashboardStampedValue",
            "description": "Distinct vehicles on open work orders right now. Count."
          },
          "overdueWorkOrders": {
            "$ref": "#/components/schemas/DashboardStampedValue",
            "description": "Open work orders past their due date right now. Count."
          },
          "completedWorkOrders": {
            "$ref": "#/components/schemas/DashboardStampedValue",
            "description": "All realized invoices ever (archived kept, deleted excluded); not scoped to the range. Count."
          },
          "unpaidInvoices": {
            "$ref": "#/components/schemas/DashboardStampedValue",
            "description": "Unpaid work-order invoices plus unpaid counter-sale invoices, all time. Count."
          },
          "unpaidInvoicesAmount": {
            "$ref": "#/components/schemas/DashboardStampedValue",
            "description": "Total open balance on those unpaid invoices, all time. DOLLARS."
          },
          "floor": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DashboardFloor"
              },
              {
                "type": "null"
              }
            ],
            "description": "Floor counters; null when the shop has no dashboard state row."
          },
          "paymentHealth": {
            "$ref": "#/components/schemas/DashboardPaymentHealth"
          },
          "collections": {
            "$ref": "#/components/schemas/DashboardCollections"
          },
          "lowStockItems": {
            "$ref": "#/components/schemas/DashboardStampedValue",
            "description": "Low-stock part count from the latest inventory snapshot. Count."
          },
          "totalParts": {
            "$ref": "#/components/schemas/DashboardStampedValue",
            "description": "Parts in inventory, from the latest inventory snapshot. Count."
          },
          "updatedAt": {
            "type": "string",
            "description": "Time of this request.",
            "format": "date-time"
          }
        },
        "required": [
          "periodRevenue",
          "monthlyRevenue",
          "periodCompleted",
          "avgPerJob",
          "revenuePctChange",
          "prevPeriodRevenue",
          "prevPeriodCompleted",
          "counterRevenue",
          "paymentsReceived",
          "cashCollected",
          "grossProfit",
          "prevPeriodGrossProfit",
          "techUtilization",
          "trendDaily",
          "customersServed",
          "floor",
          "paymentHealth",
          "collections",
          "updatedAt"
        ],
        "description": "Dashboard cards. Money is DOLLARS except trendDaily.days[*], which is cents. Fields marked optional are omitted when their source has nothing yet: vehiclesServed when vehicle tracking is incomplete in the range; activeWorkOrders, vehiclesInShop, overdueWorkOrders, completedWorkOrders, unpaidInvoices, unpaidInvoicesAmount until the shop's dashboard state row has those fields; lowStockItems and totalParts until an inventory snapshot exists. activeWorkOrders, vehiclesInShop, overdueWorkOrders, completedWorkOrders and unpaidInvoices(Amount) are right-now / all-time figures, not scoped to the range (completedWorkOrders = all realized invoices ever; unpaid = unpaid work-order invoices plus unpaid counter-sale invoices)."
      },
      "DashboardMetricsFreshness": {
        "type": "object",
        "properties": {
          "aggregatesThrough": {
            "type": [
              "string",
              "null"
            ],
            "description": "Latest write time among the stored daily rows used (current and previous period). Null when none.",
            "format": "date-time"
          },
          "floorRecountedAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Last hourly recount of the floor counters.",
            "format": "date-time"
          },
          "floorUpdatedAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Last write to the floor/unpaid state row.",
            "format": "date-time"
          },
          "unpaidAsOf": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Shop-local day of the AR snapshot that last re-anchored the unpaid totals."
          },
          "arAsOf": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Day of the AR snapshot behind paymentHealth and collections."
          },
          "inventoryAsOf": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Day of the inventory snapshot behind lowStockItems and totalParts."
          }
        },
        "required": [
          "aggregatesThrough",
          "floorRecountedAt",
          "floorUpdatedAt",
          "unpaidAsOf",
          "arAsOf",
          "inventoryAsOf"
        ],
        "description": "Age of each underlying source. The per-metric `updatedAt` values are request time and say nothing about data age."
      },
      "DashboardMetricsResponse": {
        "type": "object",
        "properties": {
          "building": {
            "type": "boolean",
            "description": "True when the stored daily rows do not reach back to the shop's first invoice (history not yet backfilled). `metrics` is then null and no card, including the floor counters, is served; the shop owner must run the history backfill."
          },
          "coverage": {
            "type": "object",
            "properties": {
              "earliestAggregateDay": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Earliest stored daily row for the shop."
              },
              "earliestInvoiceDay": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Earliest realized invoice day."
              }
            },
            "required": [
              "earliestAggregateDay",
              "earliestInvoiceDay"
            ]
          },
          "metrics": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DashboardMetrics"
              },
              {
                "type": "null"
              }
            ],
            "description": "Dashboard cards; null when building is true."
          },
          "freshness": {
            "$ref": "#/components/schemas/DashboardMetricsFreshness"
          },
          "isStale": {
            "type": "boolean",
            "description": "Always false (hard-coded)."
          },
          "lastUpdated": {
            "type": "string",
            "description": "Time of this request.",
            "format": "date-time"
          },
          "period": {
            "type": "string",
            "description": "Echo of the `period` query parameter, default 'month'. Does not affect the numbers."
          }
        },
        "required": [
          "building",
          "coverage",
          "metrics",
          "freshness",
          "isStale",
          "lastUpdated",
          "period"
        ]
      },
      "SimpleError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable, user-safe error string."
          }
        },
        "required": [
          "error"
        ],
        "description": "Error body used by most report endpoints: just an `error` string. NOT the same shape as the platform-wide `ErrorResponse` (which also requires `message`).",
        "additionalProperties": true
      },
      "ErrorWithMessage": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "description": "`error` plus an optional `message` (used by the 404 route-not-found and 500 catch-all bodies of several services).",
        "additionalProperties": true
      },
      "PermissionDeniedError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "PERMISSION_DENIED"
          },
          "message": {
            "type": "string",
            "example": "You do not have permission for reports:operational"
          },
          "missingPermissions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Permission strings the caller lacked, e.g. `reports:operational`."
          }
        },
        "required": [
          "error",
          "message",
          "missingPermissions"
        ],
        "description": "Body returned when the caller lacks a required permission.",
        "additionalProperties": true
      },
      "CustomerAgingInvoice": {
        "type": "object",
        "properties": {
          "workOrderId": {
            "type": "string"
          },
          "invoiceNumber": {
            "type": "string",
            "description": "`invoiceNumber`, else `orderNumber`, else the work-order id."
          },
          "invoiceDate": {
            "type": "string",
            "description": "Instant the invoice is considered issued: `invoicedAt`, else `invoiceDate`, else `createdAt`.",
            "format": "date-time"
          },
          "dueDate": {
            "type": "string",
            "description": "The work order's own `dueDate` if set, otherwise invoice date + 30 calendar days.",
            "format": "date-time"
          },
          "daysPastDue": {
            "type": "integer",
            "description": "Whole shop-local calendar days past the due date, clamped to 0 (never negative in this object)."
          },
          "totalAmount": {
            "type": "number",
            "description": "Invoice total (current value, not as of the date). DOLLARS as a decimal number (not cents)."
          },
          "paidAmount": {
            "type": "number",
            "description": "Payments applied on or before the as-of day, net of refunds dated on or before it. DOLLARS as a decimal number (not cents)."
          },
          "balance": {
            "type": "number",
            "description": "totalAmount - paidAmount (always > 0 here; settled invoices are omitted). DOLLARS as a decimal number (not cents)."
          },
          "bucket": {
            "type": "string",
            "enum": [
              "Current",
              "1-30",
              "31-60",
              "61-90",
              "Over 90"
            ]
          },
          "vehicle": {
            "type": "string"
          },
          "unitNumber": {
            "type": "string"
          },
          "vin": {
            "type": "string"
          },
          "archived": {
            "type": "boolean"
          }
        },
        "description": "One open invoice behind a customer's aging row (`mode=asOf` only).",
        "additionalProperties": true
      },
      "CustomerAgingRow": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string"
          },
          "customer": {
            "type": "string",
            "description": "Customer name; `Unknown` when the work order carries none."
          },
          "current": {
            "type": "number",
            "description": "Balance not yet past due. DOLLARS as a decimal number (not cents)."
          },
          "days30": {
            "type": "number",
            "description": "Balance 1-30 days past due. DOLLARS as a decimal number (not cents)."
          },
          "days60": {
            "type": "number",
            "description": "Balance 31-60 days past due. DOLLARS as a decimal number (not cents)."
          },
          "days90": {
            "type": "number",
            "description": "Balance 61-90 days past due. DOLLARS as a decimal number (not cents)."
          },
          "over90": {
            "type": "number",
            "description": "Balance more than 90 days past due. DOLLARS as a decimal number (not cents)."
          },
          "total": {
            "type": "number",
            "description": "Sum of the five buckets. DOLLARS as a decimal number (not cents)."
          },
          "invoiceCount": {
            "type": "integer",
            "description": "Open invoices contributing to this row."
          },
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerAgingInvoice"
            },
            "description": "Present in `mode=asOf`; ABSENT in `mode=snapshot` (snapshots store bucket totals only)."
          }
        },
        "required": [
          "customerId",
          "customer",
          "current",
          "days30",
          "days60",
          "days90",
          "over90",
          "total",
          "invoiceCount"
        ],
        "description": "One customer's receivables by age. Rows are sorted by `total` descending. ALL AMOUNTS IN THIS OBJECT ARE DOLLARS (floats), not cents.",
        "additionalProperties": true
      },
      "CustomerAgingResponse": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "asOf",
              "snapshot"
            ]
          },
          "asOf": {
            "type": "string",
            "description": "Echo of the requested day.",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "generatedAt": {
            "type": "string",
            "description": "`asOf` mode: request time. `snapshot` mode: when the stored snapshot was written (or request time when no snapshot exists).",
            "format": "date-time"
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerAgingRow"
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "reconstructed": {
                "type": "boolean",
                "description": "true for `asOf` (replayed from invoices + dated payments); false for `snapshot`."
              },
              "snapshotFound": {
                "type": "boolean",
                "description": "`snapshot` mode only. false means the nightly job did not store a row for that day; `rows` is then []."
              },
              "truncated": {
                "type": "boolean",
                "description": "`snapshot` mode only. true when the stored snapshot kept only the largest balances to fit the 350 KB item cap."
              },
              "untraceablePaidCents": {
                "type": "integer",
                "description": "Paid amount on in-scope invoices that have a header paid total but no dated payment rows (imported/migrated invoices); treated as paid from issue date. NOTE: this one field is CENTS while `rows` are dollars. Integer cents."
              },
              "untraceableInvoiceCount": {
                "type": "integer",
                "description": "Invoices contributing to `untraceablePaidCents` (`asOf` mode only)."
              }
            },
            "required": [
              "reconstructed"
            ],
            "additionalProperties": true
          }
        },
        "required": [
          "mode",
          "asOf",
          "generatedAt",
          "rows",
          "meta"
        ],
        "additionalProperties": true
      },
      "CustomerAgingSnapshotList": {
        "type": "object",
        "properties": {
          "dates": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            },
            "description": "Days for which a stored end-of-day aging snapshot exists, newest first."
          }
        },
        "required": [
          "dates"
        ],
        "additionalProperties": true
      },
      "WeeklyTrendPoint": {
        "type": "object",
        "properties": {
          "weekStart": {
            "type": "string",
            "description": "Monday of the week, shop-local.",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "weekEnd": {
            "type": "string",
            "description": "Sunday of the week, shop-local.",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "revenueCents": {
            "type": "integer",
            "description": "Total invoiced revenue INCLUDING tax (net-of-tax gross + taxes). Integer cents."
          },
          "laborRevenueCents": {
            "type": "integer",
            "description": "Labor revenue. Integer cents."
          },
          "partsRevenueCents": {
            "type": "integer",
            "description": "Parts revenue PLUS tires revenue. Integer cents."
          },
          "laborProfitCents": {
            "type": "integer",
            "description": "Labor revenue minus labor cost. Labor cost is hours x each technician's hourly cost rate, so this embeds the shop's technician wage cost in aggregate. Integer cents."
          },
          "partsProfitCents": {
            "type": "integer",
            "description": "Parts profit PLUS tires profit (revenue - cost). Integer cents."
          },
          "laborHours": {
            "type": "number",
            "description": "Billable labor hours for the week, rounded to 2 dp."
          },
          "jobs": {
            "type": "integer",
            "description": "Equals `invoiceCount` (the rollup sets jobsCompleted = invoiceCount)."
          },
          "customers": {
            "type": "integer",
            "description": "Distinct customers invoiced in the week."
          },
          "invoiceCount": {
            "type": "integer",
            "description": "Invoices in the week."
          }
        },
        "required": [
          "weekStart",
          "weekEnd",
          "revenueCents",
          "laborRevenueCents",
          "partsRevenueCents",
          "laborProfitCents",
          "partsProfitCents",
          "laborHours",
          "jobs",
          "customers",
          "invoiceCount"
        ],
        "additionalProperties": true
      },
      "WeeklyTrendResponse": {
        "type": "object",
        "properties": {
          "weeklyTrend": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WeeklyTrendPoint"
            },
            "description": "Oldest to newest. Weeks with no stored rollup row are simply absent, so fewer than `weeks` items can come back."
          }
        },
        "required": [
          "weeklyTrend"
        ],
        "additionalProperties": true
      },
      "VendorApVendor": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "contactPhone": {
            "type": "string"
          },
          "contactEmail": {
            "type": "string"
          },
          "accountNumber": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "additionalProperties": true
      },
      "VendorApInvoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "`po-<poId>` for invoices billed through a purchase order, `adhoc-<id>` for PO-less vendor invoices."
          },
          "vendorId": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          },
          "invoiceNumber": {
            "type": "string",
            "description": "Vendor invoice number(s); several are joined with `, `."
          },
          "poId": {
            "type": "string"
          },
          "poNumber": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "description": "Shop-local invoice day.",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "dueDate": {
            "type": "string",
            "description": "Always `date` + 30 days (fixed net-30 in code).",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "daysPastDue": {
            "type": "integer",
            "description": "Days past `dueDate` as of today (shop-local). NEGATIVE when not yet due (not clamped, unlike the customer aging endpoint)."
          },
          "agingBucket": {
            "type": "string",
            "enum": [
              "current",
              "days30",
              "days60",
              "days90",
              "over90"
            ],
            "description": "current = not yet due; days30 = 1-30 past due; days60 = 31-60; days90 = 61-90; over90 = more than 90."
          },
          "totalCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "paidCents": {
            "type": "integer",
            "description": "Equals totalCents when paid, else 0 (no partial payments at this level). Integer cents."
          },
          "balanceCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "status": {
            "type": "string",
            "enum": [
              "paid",
              "unpaid"
            ]
          },
          "paidOn": {
            "type": "string",
            "description": "Shop-local day the bill was marked paid, when recorded.",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "kind": {
            "type": "string",
            "enum": [
              "po",
              "adhoc"
            ]
          },
          "fileName": {
            "type": "string"
          },
          "itemCount": {
            "type": "integer"
          },
          "notes": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "vendorId",
          "vendorName",
          "invoiceNumber",
          "date",
          "dueDate",
          "daysPastDue",
          "agingBucket",
          "totalCents",
          "paidCents",
          "balanceCents",
          "status",
          "kind"
        ],
        "additionalProperties": true
      },
      "VendorApPurchaseOrder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "number": {
            "type": "string"
          },
          "vendorId": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "isPaid": {
            "type": "boolean"
          },
          "totalCostCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "partCount": {
            "type": "integer"
          },
          "receivedPartCount": {
            "type": "integer"
          },
          "invoiceNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "day": {
            "type": "string",
            "description": "Shop-local day of createdAt.",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "orderedDate": {
            "type": "string"
          },
          "receivedDate": {
            "type": "string"
          },
          "fulfilledDate": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "number",
          "vendorId",
          "vendorName",
          "status",
          "isPaid",
          "totalCostCents"
        ],
        "additionalProperties": true
      },
      "VendorApReturn": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "vendorId": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          },
          "purchaseOrderId": {
            "type": "string"
          },
          "purchaseOrderNumber": {
            "type": "string"
          },
          "partName": {
            "type": "string"
          },
          "partNumber": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "reason": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "completed",
              "rejected"
            ]
          },
          "refundAmountCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "createdAt": {
            "type": "string"
          },
          "day": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "notes": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "vendorId",
          "vendorName",
          "partName",
          "quantity",
          "status",
          "refundAmountCents"
        ],
        "additionalProperties": true
      },
      "VendorApCoreLine": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "vendorId": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          },
          "purchaseOrderId": {
            "type": "string"
          },
          "purchaseOrderNumber": {
            "type": "string"
          },
          "partNumber": {
            "type": "string"
          },
          "partName": {
            "type": "string"
          },
          "depositDay": {
            "type": "string",
            "description": "Shop-local day the deposit was received; '' when the line holds no deposit."
          },
          "creditDay": {
            "type": "string",
            "description": "Shop-local day the credit was recorded; '' when none."
          },
          "depositUnits": {
            "type": "number"
          },
          "depositCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "creditUnits": {
            "type": "number"
          },
          "creditCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "openUnits": {
            "type": "number",
            "description": "Deposit units no credit has matched yet."
          },
          "openCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "unmatchedCreditUnits": {
            "type": "number"
          },
          "unmatchedCreditCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "writtenOffUnits": {
            "type": "number"
          },
          "writtenOffCents": {
            "type": "integer",
            "description": "Integer cents."
          }
        },
        "description": "One purchase-order line carrying core-deposit money.",
        "additionalProperties": true
      },
      "VendorApCoreWriteOff": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "vendorId": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          },
          "partNumber": {
            "type": "string"
          },
          "units": {
            "type": "number"
          },
          "amountCents": {
            "type": "integer",
            "description": "What the closed deposits cost when written off. Integer cents."
          },
          "reason": {
            "type": "string"
          },
          "createdBy": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "day": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          }
        },
        "additionalProperties": true
      },
      "VendorApReport": {
        "type": "object",
        "properties": {
          "asOf": {
            "type": "string",
            "description": "Today in the shop's time zone. Always today: the endpoint takes NO date parameter.",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "timeZone": {
            "type": "string",
            "description": "IANA zone used for all day labels (default America/Chicago)."
          },
          "vendors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendorApVendor"
            }
          },
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendorApInvoice"
            },
            "description": "Newest invoice date first. Capped at 5000 rows (see `truncated`)."
          },
          "purchaseOrders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendorApPurchaseOrder"
            },
            "description": "Newest first. Capped at 5000 rows."
          },
          "returns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendorApReturn"
            },
            "description": "Capped at 5000 rows."
          },
          "cores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendorApCoreLine"
            },
            "description": "Capped at 5000 rows."
          },
          "coreWriteOffs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendorApCoreWriteOff"
            }
          },
          "truncated": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "NOT a boolean. Names of the sources that hit a read/row cap (any of: `purchase orders`, `vendor invoices`, `vendors`, `core write-offs`, `invoices`, `part returns`, `core lines`). Empty array = complete. When non-empty the figures are a floor."
          }
        },
        "required": [
          "asOf",
          "timeZone",
          "vendors",
          "invoices",
          "purchaseOrders",
          "returns",
          "cores",
          "coreWriteOffs",
          "truncated"
        ],
        "description": "Vendor accounts-payable report. Every money field is integer cents. There is no server-side pagination: rows are newest-first and cut at 5000 per list.",
        "additionalProperties": true
      },
      "InventoryCategoryTotals": {
        "type": "object",
        "properties": {
          "quantity": {
            "type": "number"
          },
          "costCents": {
            "type": "integer",
            "description": "Value at cost. Integer cents."
          },
          "valueCents": {
            "type": "integer",
            "description": "Value at price. Integer cents."
          }
        },
        "additionalProperties": true
      },
      "InventoryCategoryBreakdown": {
        "type": "object",
        "properties": {
          "parts": {
            "$ref": "#/components/schemas/InventoryCategoryTotals"
          },
          "tires": {
            "$ref": "#/components/schemas/InventoryCategoryTotals"
          },
          "fluids": {
            "$ref": "#/components/schemas/InventoryCategoryTotals"
          },
          "shopSupplies": {
            "$ref": "#/components/schemas/InventoryCategoryTotals"
          },
          "other": {
            "$ref": "#/components/schemas/InventoryCategoryTotals"
          },
          "grandTotal": {
            "$ref": "#/components/schemas/InventoryCategoryTotals"
          }
        },
        "description": "Inventory on hand by category at the start/end of the period (from the daily end-of-day snapshot, or a live compute where noted).",
        "additionalProperties": true
      },
      "InventoryCostChangeEvent": {
        "type": "object",
        "properties": {
          "partId": {
            "type": "string"
          },
          "partNumber": {
            "type": "string"
          },
          "partName": {
            "type": "string"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "fromCostCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "toCostCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "qtyOnHandBefore": {
            "type": "number",
            "description": "Units on hand when the cost moved."
          },
          "impactCents": {
            "type": "integer",
            "description": "qtyOnHandBefore x (toCost - fromCost); may be negative. Integer cents."
          },
          "transactionType": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "poNumber": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "PartsMovementTotals": {
        "type": "object",
        "properties": {
          "inboundQty": {
            "type": "number"
          },
          "inboundValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "purchaseValueCents": {
            "type": "integer",
            "description": "Inbound from real purchase orders. Integer cents."
          },
          "stockAddedValueCents": {
            "type": "integer",
            "description": "Inbound from stock-count / manual adds (not purchases). Integer cents."
          },
          "outboundQty": {
            "type": "number"
          },
          "outboundCostCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "outboundRevenueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "outboundProfitCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "vendorReturnValueCents": {
            "type": "integer",
            "description": "Part of outbound that is a return to vendor, not customer usage. Integer cents."
          },
          "reservedDeltaQty": {
            "type": "number",
            "description": "Net change in units held on open work orders / counter sales."
          },
          "reservedDeltaValueCents": {
            "type": "integer",
            "description": "Integer cents."
          }
        },
        "additionalProperties": true
      },
      "PartsPurchasingSummary": {
        "type": "object",
        "properties": {
          "openingValueCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Whole-inventory value at cost entering the period. null when no snapshot exists for a past start date. Integer cents."
          },
          "inboundQty": {
            "type": "number"
          },
          "inboundValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "purchaseValueCents": {
            "type": "integer",
            "description": "Real purchase-order receipts. Integer cents."
          },
          "stockAddedValueCents": {
            "type": "integer",
            "description": "Stock-count / manual adds. Integer cents."
          },
          "netPurchaseValueCents": {
            "type": "integer",
            "description": "Gross inbound minus returns to vendor. Integer cents."
          },
          "outboundQty": {
            "type": "number"
          },
          "outboundCostCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "outboundRevenueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "outboundProfitCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "vendorReturnValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "reservedDeltaQty": {
            "type": "number"
          },
          "reservedDeltaValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "closingValueCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Whole-inventory value at cost at the end of the period. Integer cents."
          },
          "adjustmentValueCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Reconciliation residual: closing - (opening + inbound - outboundCost - reservedDelta). Null when opening or closing is null. Integer cents."
          },
          "uniquePartsAffected": {
            "type": "integer"
          },
          "totalTransactions": {
            "type": "integer"
          },
          "truncated": {
            "type": "boolean",
            "description": "true when a period transaction stream hit its 20,000-row cap (env PARTS_REPORT_PERIOD_CAP can lower it), so movement totals may be understated."
          },
          "openingBreakdown": {
            "$ref": "#/components/schemas/InventoryCategoryBreakdown",
            "type": null
          },
          "closingBreakdown": {
            "$ref": "#/components/schemas/InventoryCategoryBreakdown",
            "type": null
          },
          "openingIsLive": {
            "type": "boolean"
          },
          "closingIsLive": {
            "type": "boolean"
          },
          "openingQuantityBasis": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "available",
              "physical",
              null
            ],
            "description": "Which stock the snapshot measured: available units, or physical (available + held). Null when that endpoint has no data."
          },
          "closingQuantityBasis": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "available",
              "physical",
              null
            ],
            "description": "Which stock the snapshot measured: available units, or physical (available + held). Null when that endpoint has no data."
          },
          "quantityBasisMismatch": {
            "type": "boolean"
          },
          "openingSnapshotGeneratedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "closingSnapshotGeneratedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "costChanges": {
            "type": "object",
            "properties": {
              "events": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/InventoryCostChangeEvent"
                }
              },
              "omittedCount": {
                "type": "integer"
              },
              "omittedImpactCents": {
                "type": "integer",
                "description": "Integer cents."
              },
              "totalImpactCents": {
                "type": "integer",
                "description": "Integer cents."
              }
            },
            "description": "Per-item unit-cost moves behind the revaluation residual (top 50 by impact; remainder summarised).",
            "additionalProperties": true
          },
          "categoryMovement": {
            "type": "object",
            "properties": {
              "parts": {
                "$ref": "#/components/schemas/PartsMovementTotals"
              },
              "tires": {
                "$ref": "#/components/schemas/PartsMovementTotals"
              },
              "fluids": {
                "$ref": "#/components/schemas/PartsMovementTotals"
              },
              "shopSupplies": {
                "$ref": "#/components/schemas/PartsMovementTotals"
              },
              "other": {
                "$ref": "#/components/schemas/PartsMovementTotals"
              }
            },
            "description": "Period movement split by category. Headline totals above are the sum of all five.",
            "additionalProperties": true
          }
        },
        "additionalProperties": true
      },
      "PartsPurchasingPartRow": {
        "type": "object",
        "properties": {
          "partId": {
            "type": "string"
          },
          "partNumber": {
            "type": "string"
          },
          "partName": {
            "type": "string"
          },
          "partCategory": {
            "type": "string"
          },
          "vendor": {
            "type": "string"
          },
          "openingQty": {
            "type": "number"
          },
          "openingValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "inboundQty": {
            "type": "number"
          },
          "inboundValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "outboundQty": {
            "type": "number"
          },
          "outboundCostCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "outboundRevenueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "outboundProfitCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "reservedDeltaQty": {
            "type": "number"
          },
          "reservedDeltaValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "closingQty": {
            "type": "number"
          },
          "closingValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "currentOnHand": {
            "type": "number",
            "description": "Live quantity, independent of the date range."
          },
          "currentHeldQty": {
            "type": "number",
            "description": "Live units held on open work orders / counter sales."
          },
          "currentTotalPhysical": {
            "type": "number",
            "description": "currentOnHand + currentHeldQty."
          },
          "lastActivityAt": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "part",
              "material"
            ]
          },
          "txnCount": {
            "type": "integer"
          },
          "vendors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "txnTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "txnSources": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "invoiceNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "poNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "unitLabels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "workOrderNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "description": "One part or material (tire, fluid, shop item) that had activity in the period. Sorted by most recent activity first. Only items with activity appear.",
        "additionalProperties": true
      },
      "PartsPurchasingReport": {
        "type": "object",
        "properties": {
          "dateRange": {
            "type": "object",
            "properties": {
              "startDate": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              "endDate": {
                "type": "string",
                "format": "date",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              }
            },
            "additionalProperties": true
          },
          "timeZone": {
            "type": "string"
          },
          "summary": {
            "$ref": "#/components/schemas/PartsPurchasingSummary"
          },
          "parts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartsPurchasingPartRow"
            },
            "description": "Not paginated in list mode."
          }
        },
        "required": [
          "dateRange",
          "timeZone",
          "summary",
          "parts"
        ],
        "description": "Default (list) response.",
        "additionalProperties": true
      },
      "PartsLedgerTransaction": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "itemId": {
            "type": "string"
          },
          "transactionType": {
            "type": "string"
          },
          "bucket": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound",
              "reserved",
              "noop"
            ],
            "description": "Where the report counted this transaction."
          },
          "quantityChange": {
            "type": "number"
          },
          "previousQuantity": {
            "type": [
              "number",
              "null"
            ]
          },
          "newQuantity": {
            "type": [
              "number",
              "null"
            ]
          },
          "previousCostCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "newCostCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "unitCostCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "unitPriceCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "salePriceCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "customerId": {
            "type": [
              "string",
              "null"
            ]
          },
          "workOrderNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "referenceType": {
            "type": [
              "string",
              "null"
            ]
          },
          "referenceId": {
            "type": [
              "string",
              "null"
            ]
          },
          "vendorInvoiceNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "poNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "vendorName": {
            "type": [
              "string",
              "null"
            ]
          },
          "vehicleUnitNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "vehicleVin": {
            "type": [
              "string",
              "null"
            ]
          },
          "vehicleName": {
            "type": [
              "string",
              "null"
            ]
          },
          "userId": {
            "type": "string"
          },
          "userName": {
            "type": "string",
            "description": "Who performed the stock movement (employee display name)."
          },
          "createdAt": {
            "type": "string"
          },
          "partId": {
            "type": "string",
            "description": "Present on bucket drill-down rows."
          },
          "partNumber": {
            "type": "string"
          },
          "partName": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "PartsPurchasingPartDetail": {
        "type": "object",
        "properties": {
          "partId": {
            "type": "string"
          },
          "transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartsLedgerTransaction"
            }
          },
          "page": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "description": "Response when `partId` is supplied.",
        "additionalProperties": true
      },
      "PartsPurchasingBucketDetail": {
        "type": "object",
        "properties": {
          "bucket": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound",
              "reserved"
            ]
          },
          "transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartsLedgerTransaction"
            }
          },
          "page": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "description": "Response when `bucket` is supplied.",
        "additionalProperties": true
      },
      "PartsDailyUsageRow": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "Shop-local day.",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "partId": {
            "type": "string"
          },
          "partNumber": {
            "type": "string"
          },
          "partName": {
            "type": "string"
          },
          "partCategory": {
            "type": "string"
          },
          "beginningQty": {
            "type": "number"
          },
          "purchasedQty": {
            "type": "number"
          },
          "purchaseVendors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "purchaseInvoiceNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "purchasePoNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "totalAvailableQty": {
            "type": "number"
          },
          "usedQty": {
            "type": "number"
          },
          "workOrderNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "vehicleLabels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "performedBy": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "customers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "heldDeltaQty": {
            "type": "number"
          },
          "endingQty": {
            "type": "number"
          },
          "purchasedValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "returnedQty": {
            "type": "number"
          },
          "returnedValueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "usedCostCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "usedRevenueCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "usedProfitCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "txnCount": {
            "type": "integer"
          }
        },
        "description": "One part on one shop-local day: Beginning + Purchased - Used - HeldDelta = Ending.",
        "additionalProperties": true
      },
      "PartsPurchasingDaily": {
        "type": "object",
        "properties": {
          "timeZone": {
            "type": "string"
          },
          "dailyRows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartsDailyUsageRow"
            },
            "description": "Full pivot, not paginated."
          }
        },
        "description": "Response when `view=daily`.",
        "additionalProperties": true
      },
      "PartsActivity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "transaction",
              "activity"
            ],
            "description": "`transaction` = a quantity movement; `activity` = a field edit/create event."
          },
          "activityType": {
            "type": "string",
            "description": "Free-form event name taken from the transaction/activity (e.g. reservation, adjustment, purchase_received, create, update, consumption). The distinct values present in the range are listed in `facets.types`."
          },
          "partId": {
            "type": "string"
          },
          "partNumber": {
            "type": "string"
          },
          "partName": {
            "type": "string"
          },
          "partCategory": {
            "type": "string"
          },
          "vendor": {
            "type": [
              "string",
              "null"
            ]
          },
          "quantityChange": {
            "type": [
              "number",
              "null"
            ]
          },
          "previousQuantity": {
            "type": [
              "number",
              "null"
            ]
          },
          "newQuantity": {
            "type": [
              "number",
              "null"
            ]
          },
          "unitCostCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "unitPriceCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "salePriceCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "totalValueCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "consumedQty": {
            "type": [
              "number",
              "null"
            ],
            "description": "Units sold on a `consumption` event (quantityChange is 0 there)."
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "customerId": {
            "type": [
              "string",
              "null"
            ]
          },
          "workOrderNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "referenceType": {
            "type": [
              "string",
              "null"
            ],
            "description": "Source: work_order, manual, purchase_order, ai_upload, release_queue, sales_order, ..."
          },
          "referenceId": {
            "type": [
              "string",
              "null"
            ]
          },
          "invoiceNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "poNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "vehicleId": {
            "type": [
              "string",
              "null"
            ]
          },
          "vehicleUnitNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "vehicleVin": {
            "type": [
              "string",
              "null"
            ]
          },
          "vehicleName": {
            "type": [
              "string",
              "null"
            ]
          },
          "reserved": {
            "type": "boolean"
          },
          "userId": {
            "type": "string"
          },
          "userName": {
            "type": "string",
            "description": "Employee display name who performed it."
          },
          "summary": {
            "type": "string"
          },
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Field-level edits for `activity` rows."
          },
          "createdAt": {
            "type": "string"
          },
          "children": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "`view=lifecycle` only: that part's events on the order, oldest first."
          }
        },
        "additionalProperties": true
      },
      "PartsActivityGroup": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Group value; '' is the residual bucket (listed last)."
          },
          "label": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "subtotals": {
            "type": "object",
            "properties": {
              "quantityChange": {
                "type": "number"
              },
              "enteredCents": {
                "type": "integer",
                "description": "Value entered/received. Integer cents."
              },
              "usedCents": {
                "type": "integer",
                "description": "Cost of what was used. Integer cents."
              },
              "profitCents": {
                "type": "integer",
                "description": "Integer cents."
              },
              "totalValueCents": {
                "type": "integer",
                "description": "Integer cents."
              }
            },
            "additionalProperties": true
          },
          "subGroups": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Present when `thenBy` is supplied; same shape as a group."
          }
        },
        "additionalProperties": true
      },
      "PartsActivityFacets": {
        "type": "object",
        "properties": {
          "types": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "vendors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "description": "Distinct values present in the date range BEFORE the type/source/vendor/category filters, for filter dropdowns.",
        "additionalProperties": true
      },
      "PartsActivityStats": {
        "type": "object",
        "properties": {
          "totalActivities": {
            "type": "integer"
          },
          "totalQuantityMovements": {
            "type": "number",
            "description": "Sum of |quantityChange| over the filtered set."
          },
          "totalValueImpactCents": {
            "type": "integer",
            "description": "Sum of totalValueCents over the filtered set. Integer cents."
          },
          "uniquePartsAffected": {
            "type": "integer"
          }
        },
        "additionalProperties": true
      },
      "OpeningClosingInventory": {
        "type": "object",
        "properties": {
          "openingValueCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "closingValueCents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Integer cents."
          },
          "openingIsLive": {
            "type": "boolean"
          },
          "closingIsLive": {
            "type": "boolean"
          },
          "openingBreakdown": {
            "$ref": "#/components/schemas/InventoryCategoryBreakdown",
            "type": null
          },
          "closingBreakdown": {
            "$ref": "#/components/schemas/InventoryCategoryBreakdown",
            "type": null
          },
          "openingSnapshotGeneratedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "closingSnapshotGeneratedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "openingQuantityBasis": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "available",
              "physical",
              null
            ],
            "description": "Which stock the snapshot measured: available units, or physical (available + held). Null when that endpoint has no data."
          },
          "closingQuantityBasis": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "available",
              "physical",
              null
            ],
            "description": "Which stock the snapshot measured: available units, or physical (available + held). Null when that endpoint has no data."
          },
          "quantityBasisMismatch": {
            "type": "boolean"
          }
        },
        "description": "Same opening/closing snapshot cards as the purchasing report (whole-inventory value at cost).",
        "additionalProperties": true
      },
      "PartsActivitiesResponse": {
        "type": "object",
        "properties": {
          "activities": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartsActivity"
            }
          },
          "total": {
            "type": "integer",
            "description": "Rows in the filtered set (lifecycle rows when `view=lifecycle`)."
          },
          "count": {
            "type": "integer",
            "description": "Rows on this page."
          },
          "page": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          },
          "hasMore": {
            "type": "boolean"
          },
          "facets": {
            "$ref": "#/components/schemas/PartsActivityFacets"
          },
          "inventory": {
            "$ref": "#/components/schemas/OpeningClosingInventory",
            "type": null
          },
          "truncated": {
            "type": "boolean",
            "description": "true when any source stream hit its 5000-row cap, so the list and stats are partial."
          },
          "stats": {
            "$ref": "#/components/schemas/PartsActivityStats"
          }
        },
        "required": [
          "activities",
          "total",
          "count",
          "page",
          "totalPages",
          "hasMore",
          "facets",
          "truncated",
          "stats"
        ],
        "description": "Default (paginated rows) response.",
        "additionalProperties": true
      },
      "PartsActivitiesGroupedResponse": {
        "type": "object",
        "properties": {
          "grouped": {
            "type": "boolean",
            "const": true
          },
          "groupBy": {
            "type": "string"
          },
          "thenBy": {
            "type": [
              "string",
              "null"
            ]
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PartsActivityGroup"
            },
            "description": "Sorted by absolute `totalValueCents` descending; residual '' bucket last. Not paginated."
          },
          "facets": {
            "$ref": "#/components/schemas/PartsActivityFacets"
          },
          "inventory": {
            "$ref": "#/components/schemas/OpeningClosingInventory",
            "type": null
          },
          "truncated": {
            "type": "boolean"
          },
          "stats": {
            "$ref": "#/components/schemas/PartsActivityStats"
          }
        },
        "required": [
          "grouped",
          "groupBy",
          "groups",
          "facets",
          "truncated",
          "stats"
        ],
        "description": "Response when `groupBy` is supplied (no detail rows).",
        "additionalProperties": true
      },
      "ShopFinancialMonth": {
        "type": "object",
        "properties": {
          "monthKey": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}$"
          },
          "year": {
            "type": "integer"
          },
          "month": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed",
              "archived"
            ],
            "description": "Declared type. Whether `closed` is ever stored on this row (vs the separate Period Close record) was not verified."
          },
          "totalExpensesCents": {
            "type": "integer",
            "description": "All expenses booked to the month, including any under the default 'Payroll' category. Integer cents."
          },
          "totalIncomeCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "netCents": {
            "type": "integer",
            "description": "Income minus expenses; may be negative. Integer cents."
          },
          "expenseCount": {
            "type": "integer"
          },
          "incomeCount": {
            "type": "integer"
          },
          "notes": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "monthKey",
          "year",
          "month",
          "status",
          "totalExpensesCents",
          "totalIncomeCents",
          "netCents",
          "expenseCount",
          "incomeCount"
        ],
        "additionalProperties": true
      },
      "ShopFinancialMonthList": {
        "type": "object",
        "properties": {
          "months": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ShopFinancialMonth"
            },
            "description": "Newest month first. Not paginated."
          }
        },
        "required": [
          "months"
        ],
        "additionalProperties": true
      },
      "ShopFinancialExpense": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "monthKey": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "description": "Free text; default categories include `Payroll`, `Rent/Mortgage`, `Insurance - Workers Comp`, `Utilities - Electric`, ..."
          },
          "vendor": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "amountCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "frequency": {
            "type": "string",
            "enum": [
              "monthly",
              "weekly",
              "one-time",
              "quarterly",
              "annual"
            ]
          },
          "startDate": {
            "type": "string"
          },
          "endDate": {
            "type": "string"
          },
          "paymentStatus": {
            "type": "string",
            "enum": [
              "paid",
              "unpaid",
              "scheduled"
            ],
            "description": "Promoted to `paid` when the expense is linked to a cleared bank transaction."
          },
          "paymentMethod": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "isFixed": {
            "type": "boolean"
          },
          "isTaxDeductible": {
            "type": "boolean"
          },
          "costCenter": {
            "type": "string"
          },
          "receiptExtracted": {
            "type": "boolean"
          },
          "sourceTransactionId": {
            "type": "string",
            "description": "Set when promoted from a bank transaction."
          },
          "sourceTransaction": {
            "type": "object",
            "properties": {
              "transactionId": {
                "type": "string"
              },
              "date": {
                "type": "string",
                "description": "Day the money left the account."
              },
              "name": {
                "type": "string",
                "description": "Merchant/bank description."
              },
              "amountCents": {
                "type": "integer",
                "description": "Signed cents; an expense's source is negative. Integer cents."
              },
              "accountName": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "description": "Added at read time for bank-linked expenses.",
            "additionalProperties": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "monthKey",
          "category",
          "description",
          "amountCents"
        ],
        "description": "One expense line. Free-text fields (`vendor`, `description`, `notes`) are whatever the shop typed.",
        "additionalProperties": true
      },
      "ShopFinancialIncome": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "monthKey": {
            "type": "string"
          },
          "customerId": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "amountCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "frequency": {
            "type": "string",
            "enum": [
              "monthly",
              "weekly",
              "one-time"
            ]
          },
          "paymentStatus": {
            "type": "string",
            "enum": [
              "unpaid",
              "partially_paid",
              "paid"
            ],
            "description": "Promoted from the linked counter sale at read time; never demoted."
          },
          "invoiceId": {
            "type": "string"
          },
          "invoiceNumber": {
            "type": "string",
            "description": "Counter-sale number, e.g. SO-000123."
          },
          "notes": {
            "type": "string"
          },
          "saleStatus": {
            "type": [
              "string",
              "null"
            ],
            "description": "Linked counter sale status (read-time enrichment)."
          },
          "salePaidCents": {
            "type": "integer",
            "description": "Amount paid on the linked counter sale (read-time enrichment). Integer cents."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "monthKey",
          "category",
          "amountCents"
        ],
        "additionalProperties": true
      },
      "ShopFinancialTransaction": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "monthKey": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "expense_payment",
              "income_receipt"
            ]
          },
          "referenceId": {
            "type": "string",
            "description": "Expense or income id."
          },
          "amountCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "date": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "monthKey",
          "type",
          "referenceId",
          "amountCents",
          "date"
        ],
        "additionalProperties": true
      },
      "ShopFinancialMonthDetail": {
        "type": "object",
        "properties": {
          "month": {
            "$ref": "#/components/schemas/ShopFinancialMonth"
          },
          "expenses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ShopFinancialExpense"
            },
            "description": "All expenses for the month (drained fully)."
          },
          "income": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ShopFinancialIncome"
            },
            "description": "All income entries for the month."
          },
          "transactions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ShopFinancialTransaction"
            },
            "description": "Recorded payments/receipts against expenses and income."
          }
        },
        "required": [
          "month",
          "expenses",
          "income",
          "transactions"
        ],
        "additionalProperties": true
      },
      "TechnicianLaborBreakdownEntry": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string"
          },
          "orderNumber": {
            "type": "string",
            "description": "Invoice number, else order number, else id."
          },
          "isInvoiced": {
            "type": "boolean"
          },
          "status": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "description": "Invoiced/created timestamp of the work order."
          },
          "customerName": {
            "type": "string"
          },
          "vehicleLabel": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "Labor line description."
          },
          "hours": {
            "type": "number",
            "description": "This technician's share of the line's hours."
          },
          "revenueCents": {
            "type": "integer",
            "description": "This technician's share of the line's labor revenue (net of discount). Integer cents."
          },
          "costCents": {
            "type": "integer",
            "description": "PAY DATA. Hours x the technician's hourly cost rate in force on the line's date (or the stored line cost). Dividing by `hours` reveals the rate. OMITTED for callers without reports:profit / attendance:financials; API keys (role admin) always receive it. Integer cents."
          }
        },
        "required": [
          "orderId",
          "orderNumber",
          "isInvoiced",
          "status",
          "date",
          "customerName",
          "vehicleLabel",
          "description",
          "hours",
          "revenueCents"
        ],
        "additionalProperties": true
      },
      "TechnicianLaborRow": {
        "type": "object",
        "properties": {
          "technicianId": {
            "type": "string"
          },
          "technicianName": {
            "type": "string"
          },
          "laborHours": {
            "type": "number",
            "description": "Completed labor hours attributed to this technician in the window."
          },
          "laborRevenueCents": {
            "type": "integer",
            "description": "Labor billed for those hours (labor only; parts excluded by design). Integer cents."
          },
          "laborCostCents": {
            "type": "integer",
            "description": "PAY DATA. What the shop pays for those hours (hourly cost rate x hours; weekly-flat staff are prorated). OMITTED for callers without reports:profit or attendance:financials. Integer cents."
          },
          "commissionCents": {
            "type": "integer",
            "description": "PAY DATA. Commission earned on those hours at the technician's labor-commission %. OMITTED for callers without reports:profit or attendance:financials. Integer cents."
          },
          "jobsCompleted": {
            "type": "integer",
            "description": "Distinct work orders contributing."
          },
          "dailyHours": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "description": "Hours keyed by the shop-local day (YYYY-MM-DD) each line counted on under the basis."
          },
          "breakdown": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TechnicianLaborBreakdownEntry"
            },
            "description": "One entry per completed labor line (can be large)."
          }
        },
        "required": [
          "technicianId",
          "technicianName",
          "laborHours",
          "laborRevenueCents",
          "jobsCompleted",
          "dailyHours",
          "breakdown"
        ],
        "additionalProperties": true
      },
      "TechnicianLaborSummaryResponse": {
        "type": "object",
        "properties": {
          "technicians": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TechnicianLaborRow"
            },
            "description": "Sorted by laborRevenueCents descending."
          },
          "startDate": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "endDate": {
            "type": "string",
            "format": "date",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "basis": {
            "type": "string",
            "enum": [
              "labor-completed",
              "invoiced"
            ],
            "description": "Which date decides the period: the day each labor line was completed, or the day its work order was invoiced."
          },
          "workOrdersScanned": {
            "type": "integer"
          },
          "truncated": {
            "type": "boolean",
            "description": "true when the 5000-work-order read cap was hit; totals are then partial."
          }
        },
        "required": [
          "technicians",
          "startDate",
          "endDate",
          "basis",
          "workOrdersScanned",
          "truncated"
        ],
        "additionalProperties": true
      },
      "CustomerUnpaidInvoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Work order or counter-sale id."
          },
          "orderNumber": {
            "type": "string"
          },
          "orderName": {
            "type": "string",
            "description": "Title, truncated to 60 chars."
          },
          "description": {
            "type": "string"
          },
          "vehicle": {
            "type": "string"
          },
          "vehicleId": {
            "type": "string"
          },
          "vehicleVin": {
            "type": "string"
          },
          "vehicleUnitNumber": {
            "type": "string"
          },
          "poNumber": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "description": "Creation timestamp."
          },
          "invoicedDate": {
            "type": "string"
          },
          "dueDate": {
            "type": "string"
          },
          "totalAmountCents": {
            "type": "integer",
            "description": "Active total (declined services excluded; shop-supplies cap applied). Integer cents."
          },
          "paidAmountCents": {
            "type": "integer",
            "description": "Net of refunds, computed from the Payments table (not the work-order header). Integer cents."
          },
          "balanceCents": {
            "type": "integer",
            "description": "Always > 0 in this list. Integer cents."
          },
          "total": {
            "type": "number",
            "description": "Dollar twin of totalAmountCents. DOLLARS as a decimal number (not cents)."
          },
          "paid": {
            "type": "number",
            "description": "Dollar twin of paidAmountCents. DOLLARS as a decimal number (not cents)."
          },
          "balance": {
            "type": "number",
            "description": "Dollar twin of balanceCents. DOLLARS as a decimal number (not cents)."
          },
          "status": {
            "type": "string"
          },
          "archived": {
            "type": "boolean",
            "description": "Archived but still unpaid invoices ARE included."
          },
          "sourceType": {
            "type": "string",
            "enum": [
              "wo",
              "so"
            ],
            "description": "`wo` = work order invoice, `so` = counter sale."
          }
        },
        "required": [
          "id",
          "orderNumber",
          "totalAmountCents",
          "paidAmountCents",
          "balanceCents",
          "sourceType"
        ],
        "additionalProperties": true
      },
      "CustomerUnpaidInvoicesResponse": {
        "type": "object",
        "properties": {
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerUnpaidInvoice"
            },
            "description": "Oldest invoiced date first."
          },
          "truncated": {
            "type": "boolean",
            "description": "true when the customer had more than 1500 open invoices and only the 1500 most recent were evaluated; narrow with startDate/endDate."
          }
        },
        "required": [
          "invoices",
          "truncated"
        ],
        "additionalProperties": true
      },
      "StatementPayment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "invoiceId": {
            "type": "string"
          },
          "orderNumber": {
            "type": "string"
          },
          "date": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "amountCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "amount": {
            "type": "number",
            "description": "Dollar twin of amountCents. DOLLARS as a decimal number (not cents)."
          },
          "reference": {
            "type": "string"
          },
          "checkNumber": {
            "type": "string"
          },
          "bankName": {
            "type": "string"
          },
          "referenceNumber": {
            "type": "string"
          },
          "cardLast4": {
            "type": "string"
          },
          "cardBrand": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "isRefund": {
            "type": "boolean"
          },
          "status": {
            "type": "string"
          },
          "bulkPaymentId": {
            "type": "string"
          },
          "bulkPaymentKind": {
            "type": "string"
          },
          "orderNumbers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": true
      },
      "StatementInvoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "orderNumber": {
            "type": "string"
          },
          "orderName": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "vehicle": {
            "type": "string"
          },
          "vehicleId": {
            "type": "string"
          },
          "vehicleVin": {
            "type": "string"
          },
          "vehicleUnitNumber": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "date": {
            "type": "string"
          },
          "invoicedDate": {
            "type": "string"
          },
          "dueDate": {
            "type": "string"
          },
          "totalAmountCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "paidAmountCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "balanceCents": {
            "type": "integer",
            "description": "Can be NEGATIVE (overpayment). Integer cents."
          },
          "creditedFromOverpaymentCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "creditAppliedCents": {
            "type": "integer",
            "description": "Portion paid with store credit. Integer cents."
          },
          "total": {
            "type": "number",
            "description": "DOLLARS as a decimal number (not cents)."
          },
          "paid": {
            "type": "number",
            "description": "DOLLARS as a decimal number (not cents)."
          },
          "balance": {
            "type": "number",
            "description": "DOLLARS as a decimal number (not cents)."
          },
          "status": {
            "type": "string"
          },
          "sourceType": {
            "type": "string",
            "enum": [
              "wo",
              "so"
            ]
          },
          "payments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatementPayment"
            }
          }
        },
        "additionalProperties": true
      },
      "CustomerStatement": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "customerId": {
            "type": "string"
          },
          "statementNumber": {
            "type": "string",
            "description": "`ST-` prefixed."
          },
          "invoiceIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "totalAmountCents": {
            "type": "integer",
            "description": "Sum of invoice totals, recomputed live on every read. Integer cents."
          },
          "paidAmountCents": {
            "type": "integer",
            "description": "Recomputed live. Integer cents."
          },
          "totalDueCents": {
            "type": "integer",
            "description": "Sum of POSITIVE invoice balances only (an overpaid invoice does not offset another's due). Integer cents."
          },
          "creditAppliedCents": {
            "type": "integer",
            "description": "Integer cents."
          },
          "totalAmount": {
            "type": "number",
            "description": "DOLLARS as a decimal number (not cents)."
          },
          "paidAmount": {
            "type": "number",
            "description": "DOLLARS as a decimal number (not cents)."
          },
          "totalDue": {
            "type": "number",
            "description": "DOLLARS as a decimal number (not cents)."
          },
          "status": {
            "type": "string",
            "description": "`Draft` when created; recomputed on read to `Paid` (nothing due) or `Partial` (something paid). A statement that has been sent may carry other values - not enumerated."
          },
          "includeInvoices": {
            "type": "boolean"
          },
          "startDate": {
            "type": "string"
          },
          "endDate": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatementInvoice"
            },
            "description": "Live-resolved at read time, not the stored copy. Only present/refreshed when invoiceIds is non-empty."
          },
          "payments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatementPayment"
            }
          },
          "sentAt": {
            "type": "string",
            "description": "Set when the statement was sent to the customer."
          },
          "sentVia": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "customerId",
          "statementNumber",
          "invoiceIds",
          "totalAmountCents",
          "paidAmountCents",
          "totalDueCents",
          "status"
        ],
        "additionalProperties": true
      },
      "CustomerStatementList": {
        "type": "object",
        "properties": {
          "statements": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerStatement"
            },
            "description": "Newest first. No pagination or truncation flag."
          }
        },
        "required": [
          "statements"
        ],
        "additionalProperties": true
      },
      "Payment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "UUID, or `manual_<Idempotency-Key>` for idempotent creates."
          },
          "tenantId": {
            "type": "string"
          },
          "workOrderId": {
            "type": "string",
            "description": "Work order OR counter-sale id the payment is applied to."
          },
          "customerId": {
            "type": [
              "string",
              "null"
            ]
          },
          "orderNumber": {
            "type": "string"
          },
          "method": {
            "type": "string",
            "description": "Free-form string, not validated server-side (e.g. cash, card, check, ach, zelle, credit)."
          },
          "amountCents": {
            "type": "integer",
            "description": "Total collected = principal + card surcharge. Can be negative for adjustments. Integer cents."
          },
          "surchargeAmountCents": {
            "type": "integer",
            "description": "Card-surcharge part of amountCents; absent when none. Integer cents."
          },
          "surchargeFee": {
            "type": "number",
            "description": "Surcharge percent applied."
          },
          "appliedToInvoiceCents": {
            "type": "integer",
            "description": "Principal actually applied when an overpayment was split to store credit; absent otherwise. Integer cents."
          },
          "creditedToCustomerCents": {
            "type": "integer",
            "description": "Overpayment excess parked as store credit; absent otherwise. Integer cents."
          },
          "status": {
            "type": "string",
            "description": "`completed` on create; also `refunded`, `voided`, `pending`, `failed` elsewhere in the API."
          },
          "manualPaymentDetails": {
            "type": "object",
            "additionalProperties": true,
            "description": "Card brand/last4 for payments run on the shop's own terminal."
          },
          "stripePaymentDetails": {
            "type": "object",
            "additionalProperties": true,
            "description": "Present on online (Stripe) payments."
          },
          "referenceNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "checkNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "bankName": {
            "type": [
              "string",
              "null"
            ]
          },
          "zelleEmail": {
            "type": [
              "string",
              "null"
            ],
            "description": "Payer PII."
          },
          "zellePhone": {
            "type": [
              "string",
              "null"
            ],
            "description": "Payer PII."
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdBy": {
            "type": "string"
          },
          "createdByName": {
            "type": "string",
            "description": "Employee who recorded the payment."
          },
          "createdAt": {
            "type": "string",
            "description": "Payment timestamp (may be backdated for migrated payments)."
          },
          "paymentDate": {
            "type": "string",
            "description": "Legacy/edited alias of createdAt."
          },
          "date": {
            "type": "string",
            "description": "Legacy alias."
          },
          "createdAtOriginal": {
            "type": "string",
            "description": "Present once an admin edited the date."
          },
          "updatedAt": {
            "type": "string"
          },
          "refundedAmountCents": {
            "type": "integer",
            "description": "Present on refunded payments. Integer cents."
          },
          "refundedAt": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "description": "LEGACY rows only: dollar amount. Prefer amountCents. DOLLARS as a decimal number (not cents)."
          }
        },
        "required": [
          "id",
          "method",
          "amountCents",
          "createdAt"
        ],
        "description": "A stored payment row, returned as stored (including internal fields that are not part of the contract). Work-order payments and counter-sale payments are merged; counter-sale rows may differ in field set (not enumerated).",
        "additionalProperties": true
      },
      "PaymentListResponse": {
        "type": "object",
        "properties": {
          "payments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Payment"
            },
            "description": "Merged work-order + counter-sale payments, sorted newest-first by createdAt WITHIN this page only."
          },
          "total": {
            "type": "integer",
            "description": "Number of payments on THIS page (not the all-time or in-range total)."
          },
          "nextCursor": {
            "type": "string",
            "description": "Opaque base64 cursor. Pass back as `cursor` to continue. Absent on the last page."
          },
          "hasMore": {
            "type": "boolean",
            "description": "true when `nextCursor` is present."
          }
        },
        "required": [
          "payments",
          "total",
          "hasMore"
        ],
        "additionalProperties": true
      }
    }
  },
  "tags": [
    {
      "name": "Reports",
      "description": "Sales, payments, tax, commission, parts and accounts-receivable reports. Check x-money-units on each operation: many report fields are decimal dollars, not cents."
    },
    {
      "name": "Digests",
      "description": "Daily and weekly Smart Digest: a deterministic snapshot of the numbers plus a narrative written from them."
    },
    {
      "name": "Dashboard",
      "description": "Dashboard feeds."
    }
  ],
  "paths": {
    "/inventory/receiving": {
      "post": {
        "summary": "Push dealer invoice line items",
        "description": "Receives already-parsed dealer invoice line items. In draft mode (default), creates or updates a draft Purchase Order for review without immediately modifying inventory, relaxing vendor requirements. In receive mode, updates stock immediately.",
        "operationId": "receiveInvoiceLines",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" },
          { "$ref": "#/components/parameters/AgentNameHeader" },
          { "$ref": "#/components/parameters/AgentRunIdHeader" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ReceivingRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invoice successfully imported or draft PO created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ReceivingResponse" }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          },
          "404": {
            "description": "PO not found or vendor not found in receive mode",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          },
          "409": {
            "description": "Conflict: duplicate invoice, invoice in progress, PO already received, or vendor mismatch",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          },
          "422": {
            "description": "Ambiguous part number in receive mode",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          },
          "500": {
            "description": "Internal processing failure",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          }
        }
      }
    },
    "/inventory": {
      "get": {
        "summary": "List inventory items",
        "description": "Retrieve parts and inventory with optional filters and keyword search.",
        "operationId": "listInventory",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "category", "in": "query", "schema": { "type": "string" }, "description": "Filter by category" },
          { "name": "search", "in": "query", "schema": { "type": "string" }, "description": "Search part number or name" },
          { "name": "lowStock", "in": "query", "schema": { "type": "boolean" }, "description": "Filter to items below reorder point" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50 } },
          { "name": "lastEvaluatedKey", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "List of inventory items",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": { "type": "array", "items": { "$ref": "#/components/schemas/InventoryItem" } },
                    "count": { "type": "integer" },
                    "lastEvaluatedKey": { "type": "string", "nullable": true }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create inventory item",
        "description": "Add a new inventory part or supply item.",
        "operationId": "createInventoryItem",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" },
          { "$ref": "#/components/parameters/AgentNameHeader" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["partNumber", "name", "unitCostCents"],
                "properties": {
                  "partNumber": { "type": "string" },
                  "name": { "type": "string" },
                  "description": { "type": "string" },
                  "category": { "type": "string" },
                  "quantity": { "type": "number", "default": 0 },
                  "unitCostCents": { "type": "integer" },
                  "unitPriceCents": { "type": "integer" },
                  "binLocation": { "type": "string" },
                  "reorderPoint": { "type": "number" },
                  "vendorId": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Item created",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InventoryItem" } } }
          }
        }
      }
    },
    "/inventory/{id}": {
      "get": {
        "summary": "Get inventory item by ID",
        "operationId": "getInventoryItem",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Item details",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InventoryItem" } } }
          },
          "404": { "description": "Item not found" }
        }
      },
      "patch": {
        "summary": "Update inventory item",
        "operationId": "updateInventoryItem",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": { "type": "string" },
                  "description": { "type": "string" },
                  "category": { "type": "string" },
                  "unitCostCents": { "type": "integer" },
                  "unitPriceCents": { "type": "integer" },
                  "quantity": { "type": "number" },
                  "binLocation": { "type": "string" },
                  "reorderPoint": { "type": "number" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated item",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InventoryItem" } } }
          }
        }
      }
    },
    "/work-orders": {
      "get": {
        "summary": "List work orders",
        "description": "List work orders with status, date, or vehicle filters.",
        "operationId": "listWorkOrders",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string" } },
          { "name": "customerId", "in": "query", "schema": { "type": "string" } },
          { "name": "vehicleId", "in": "query", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50 } },
          { "name": "lastEvaluatedKey", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "List of work orders",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workOrders": { "type": "array", "items": { "$ref": "#/components/schemas/WorkOrder" } },
                    "count": { "type": "integer" },
                    "lastEvaluatedKey": { "type": "string", "nullable": true }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create work order",
        "operationId": "createWorkOrder",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" },
          { "$ref": "#/components/parameters/AgentNameHeader" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["customerId", "vehicleId", "complaint"],
                "properties": {
                  "customerId": { "type": "string" },
                  "vehicleId": { "type": "string" },
                  "complaint": { "type": "string" },
                  "priority": { "type": "string", "enum": ["low", "medium", "high", "urgent"], "default": "medium" },
                  "status": { "type": "string", "enum": ["draft", "estimate", "approved"], "default": "draft" },
                  "notes": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Work order created",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkOrder" } } }
          }
        }
      }
    },
    "/work-orders/{id}": {
      "get": {
        "summary": "Get work order by ID",
        "description": "Returns full work order details including service blocks, parts, labor lines, and customer/vehicle data.",
        "operationId": "getWorkOrder",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Full work order",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkOrder" } } }
          },
          "404": { "description": "Work order not found" }
        }
      },
      "patch": {
        "summary": "Update work order",
        "operationId": "updateWorkOrder",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": { "type": "string" },
                  "priority": { "type": "string" },
                  "complaint": { "type": "string" },
                  "notes": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated work order",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkOrder" } } }
          }
        }
      }
    },
    "/work-orders/{id}/services": {
      "post": {
        "summary": "Add service block to work order",
        "operationId": "addWorkOrderService",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": { "type": "string", "example": "Brake System Service" },
                  "description": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Service added" }
        }
      }
    },
    "/work-orders/{id}/services/{svcId}/items": {
      "post": {
        "summary": "Add line item to service block",
        "operationId": "addWorkOrderLineItem",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "svcId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["kind", "name"],
                "properties": {
                  "kind": { "type": "string", "enum": ["labor", "part", "tire", "material", "fee"] },
                  "name": { "type": "string" },
                  "partNumber": { "type": "string" },
                  "quantity": { "type": "number", "default": 1 },
                  "unitCostCents": { "type": "integer" },
                  "unitPriceCents": { "type": "integer" },
                  "hours": { "type": "number" },
                  "technicianId": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Line item added" }
        }
      }
    },
    "/customers": {
      "get": {
        "summary": "List customers",
        "operationId": "listCustomers",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "search", "in": "query", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50 } },
          { "name": "lastEvaluatedKey", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "List of customers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "customers": { "type": "array", "items": { "$ref": "#/components/schemas/Customer" } },
                    "count": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create customer",
        "operationId": "createCustomer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": { "type": "string" },
                  "companyName": { "type": "string" },
                  "email": { "type": "string", "format": "email" },
                  "phone": { "type": "string" },
                  "dotNumber": { "type": "string" },
                  "address": { "type": "string" },
                  "notes": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Customer created",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Customer" } } }
          }
        }
      }
    },
    "/customers/{id}": {
      "get": {
        "summary": "Get customer by ID",
        "operationId": "getCustomer",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Customer details",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Customer" } } }
          },
          "404": { "description": "Customer not found" }
        }
      },
      "patch": {
        "summary": "Update customer",
        "operationId": "updateCustomer",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": { "type": "string" },
                  "companyName": { "type": "string" },
                  "email": { "type": "string" },
                  "phone": { "type": "string" },
                  "address": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated customer",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Customer" } } }
          }
        }
      }
    },
    "/vehicles": {
      "get": {
        "summary": "List vehicles",
        "operationId": "listVehicles",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "customerId", "in": "query", "schema": { "type": "string" } },
          { "name": "search", "in": "query", "schema": { "type": "string" }, "description": "Search VIN, unit number or license plate" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50 } }
        ],
        "responses": {
          "200": {
            "description": "List of vehicles",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vehicles": { "type": "array", "items": { "$ref": "#/components/schemas/Vehicle" } },
                    "count": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create vehicle",
        "operationId": "createVehicle",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["vin", "customerId"],
                "properties": {
                  "vin": { "type": "string" },
                  "customerId": { "type": "string" },
                  "unitNumber": { "type": "string" },
                  "make": { "type": "string" },
                  "model": { "type": "string" },
                  "year": { "type": "integer" },
                  "licensePlate": { "type": "string" },
                  "mileage": { "type": "number" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Vehicle created",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Vehicle" } } }
          }
        }
      }
    },
    "/vehicles/{id}": {
      "get": {
        "summary": "Get vehicle by ID",
        "operationId": "getVehicle",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Vehicle details",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Vehicle" } } }
          },
          "404": { "description": "Vehicle not found" }
        }
      }
    },
    "/service-requests": {
      "get": {
        "summary": "List service requests / intake appointments",
        "operationId": "listServiceRequests",
        "x-read-only-key": "allowed",
        "responses": {
          "200": {
            "description": "List of service requests",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "requests": { "type": "array", "items": { "$ref": "#/components/schemas/ServiceRequest" } }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create service request or intake appointment",
        "description": "Public or authed intake endpoint for creating customer appointments or roadside service requests.",
        "operationId": "createServiceRequest",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" },
          { "$ref": "#/components/parameters/AgentNameHeader" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["customerName", "phone", "description"],
                "properties": {
                  "customerName": { "type": "string" },
                  "phone": { "type": "string" },
                  "email": { "type": "string" },
                  "vehicleVin": { "type": "string" },
                  "description": { "type": "string" },
                  "preferredDate": { "type": "string", "format": "date" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Service request created",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ServiceRequest" } } }
          }
        }
      }
    },
    "/purchase-orders": {
      "get": {
        "summary": "List purchase orders",
        "description": "List purchase orders for the shop. Filter by status (e.g. 'ordered'), vendor ID, or date window. Filtering by status=ordered is recommended for AI agents to inspect open orders and match incoming dealer invoices.",
        "operationId": "listPurchaseOrders",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["draft", "ordered", "partially_received", "received", "fully_received", "cancelled"] }, "description": "Filter by PO status (use 'ordered' to match incoming shipments)" },
          { "name": "vendorId", "in": "query", "schema": { "type": "string" }, "description": "Filter by vendor ID" },
          { "name": "vendorInvoiceNumber", "in": "query", "schema": { "type": "string" }, "description": "Filter by vendor invoice number" },
          { "name": "orderId", "in": "query", "schema": { "type": "string" }, "description": "Filter by linked work order ID" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 100 }, "description": "Max POs to return (default 100, max 5000)" },
          { "name": "dateFrom", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "Start date (YYYY-MM-DD)" },
          { "name": "dateTo", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "End date (YYYY-MM-DD)" },
          { "name": "view", "in": "query", "schema": { "type": "string", "enum": ["summary", "invoice-index"] }, "description": "Summary view strips heavy collections for lighter payloads" }
        ],
        "responses": {
          "200": {
            "description": "List of purchase orders",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "purchaseOrders": { "type": "array", "items": { "$ref": "#/components/schemas/PurchaseOrder" } },
                    "count": { "type": "integer" },
                    "truncated": { "type": "boolean" }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create purchase order",
        "description": "Create a new purchase order with line items. Supports Idempotency-Key header.",
        "operationId": "createPurchaseOrder",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "vendorName": { "type": "string", "example": "FleetPride" },
                  "vendorId": { "type": "string" },
                  "status": { "type": "string", "enum": ["draft", "ordered"], "default": "draft" },
                  "note": { "type": "string" },
                  "vendorInvoiceNumber": { "type": "string" },
                  "parts": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": ["partNumber", "quantity"],
                      "properties": {
                        "partNumber": { "type": "string", "example": "BWP-M-1234" },
                        "description": { "type": "string", "example": "Brake Shoe Kit" },
                        "quantity": { "type": "number", "example": 4 },
                        "unitCost": { "type": "number", "example": 65.50 },
                        "unitCostCents": { "type": "integer", "example": 6550 }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Purchase order created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "purchaseOrder": { "$ref": "#/components/schemas/PurchaseOrder" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/purchase-orders/{id}": {
      "get": {
        "summary": "Get purchase order details",
        "description": "Retrieve a single purchase order by ID including line items, received counts, unit costs, and audit history.",
        "operationId": "getPurchaseOrder",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Purchase order ID" }
        ],
        "responses": {
          "200": {
            "description": "Purchase order details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "purchaseOrder": { "$ref": "#/components/schemas/PurchaseOrder" }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Purchase order not found",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          }
        }
      }
    },
    "/purchase-orders/{id}/receive": {
      "post": {
        "summary": "Receive parts on a purchase order",
        "description": "Receive parts on an existing purchase order directly into shop inventory. Sets parts received, updates stock counts and unit costs atomically, and advances the PO status.",
        "operationId": "receivePurchaseOrder",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Purchase order ID" },
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "receivedAll": { "type": "boolean", "default": true, "description": "If true, receives all outstanding parts on the PO" },
                  "parts": {
                    "type": "array",
                    "description": "Optional line-by-line receiving list",
                    "items": {
                      "type": "object",
                      "required": ["partId", "quantity"],
                      "properties": {
                        "partId": { "type": "string" },
                        "quantity": { "type": "number" },
                        "expectedQuantityReceived": { "type": "number" }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Purchase order received and inventory updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "message": { "type": "string", "example": "Purchase order received successfully" },
                    "purchaseOrder": { "$ref": "#/components/schemas/PurchaseOrder" }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Purchase order not found",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          },
          "409": {
            "description": "Conflict: PO already received or concurrent receive in progress",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          }
        }
      }
    },
    "/vendors": {
      "get": {
        "summary": "List vendors",
        "operationId": "listVendors",
        "x-read-only-key": "allowed",
        "responses": {
          "200": { "description": "List of vendors" }
        }
      },
      "post": {
        "summary": "Create vendor",
        "operationId": "createVendor",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": { "type": "string" },
                  "accountNumber": { "type": "string" },
                  "phone": { "type": "string" },
                  "email": { "type": "string" },
                  "notes": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Vendor created" }
        }
      }
    },
    "/inspections": {
      "get": {
        "summary": "List inspection records",
        "operationId": "listInspections",
        "x-read-only-key": "allowed",
        "parameters": [
          { "name": "vehicleId", "in": "query", "schema": { "type": "string" } },
          { "name": "workOrderId", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "List of vehicle inspections" }
        }
      }
    },
    "/users/me": {
      "get": {
        "summary": "Get authenticated user profile",
        "operationId": "getCurrentUser",
        "x-read-only-key": "allowed",
        "responses": {
          "200": { "description": "User profile" }
        }
      }
    },
    "/webhooks": {
      "get": {
        "summary": "List configured webhook subscriptions",
        "operationId": "listWebhooks",
        "x-read-only-key": "never",
        "responses": {
          "200": {
            "description": "List of active and configured webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/WebhookSubscription" }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a new webhook subscription",
        "operationId": "createWebhook",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "url", "events"],
                "properties": {
                  "name": { "type": "string", "example": "Parts Sync Bot" },
                  "url": { "type": "string", "format": "uri", "example": "https://agent.example.com/webhooks" },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "*",
                        "inventory.created",
                        "inventory.updated",
                        "purchase_order.created",
                        "purchase_order.updated",
                        "purchase_order.received",
                        "work_order.created",
                        "work_order.updated",
                        "work_order.status_changed",
                        "invoice.created",
                        "payment.received",
                        "customer.created",
                        "vehicle.created",
                        "service_request.created",
                        "service_request.converted",
                        "sales_order.created",
                        "sales_order.completed",
                        "sales_order.refunded",
                        "webhook.test"
                      ]
                    },
                    "example": ["service_request.created", "sales_order.completed", "purchase_order.received"]
                  },
                  "secret": {
                    "type": "string",
                    "description": "Optional custom signing secret (minimum 16 characters). If omitted, an HMAC SHA-256 secret is generated automatically.",
                    "example": "my-custom-secret-key-12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook created with unmasked secret (whsec_...)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/WebhookSubscription" }
              }
            }
          }
        }
      }
    },
    "/webhooks/events": {
      "get": {
        "summary": "List available webhook event types",
        "operationId": "listWebhookEvents",
        "x-read-only-key": "never",
        "responses": {
          "200": {
            "description": "Catalogue of all available event types",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/WebhookEventInfo" }
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{id}": {
      "get": {
        "summary": "Get webhook details",
        "operationId": "getWebhook",
        "x-read-only-key": "never",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Webhook details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/WebhookSubscription" }
              }
            }
          },
          "404": { "description": "Webhook not found" }
        }
      },
      "patch": {
        "summary": "Update webhook subscription",
        "operationId": "updateWebhook",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": { "type": "string" },
                  "url": { "type": "string", "format": "uri" },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "*",
                        "inventory.created",
                        "inventory.updated",
                        "purchase_order.created",
                        "purchase_order.updated",
                        "purchase_order.received",
                        "work_order.created",
                        "work_order.updated",
                        "work_order.status_changed",
                        "invoice.created",
                        "payment.received",
                        "customer.created",
                        "vehicle.created",
                        "service_request.created",
                        "service_request.converted",
                        "sales_order.created",
                        "sales_order.completed",
                        "sales_order.refunded",
                        "webhook.test"
                      ]
                    }
                  },
                  "isActive": { "type": "boolean" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated webhook",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/WebhookSubscription" }
              }
            }
          },
          "404": { "description": "Webhook not found" }
        }
      },
      "delete": {
        "summary": "Delete webhook subscription",
        "operationId": "deleteWebhook",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Webhook deleted" },
          "404": { "description": "Webhook not found" }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "get": {
        "summary": "List recent delivery attempts for a webhook",
        "operationId": "listWebhookDeliveries",
        "x-read-only-key": "never",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "required": false, "schema": { "type": "integer", "default": 20, "maximum": 100 } }
        ],
        "responses": {
          "200": { "description": "Newest-first delivery log entries: event, status, HTTP status code, duration and error" },
          "404": { "description": "Webhook not found" }
        }
      }
    },
    "/webhooks/{id}/test": {
      "post": {
        "summary": "Send a test ping event to webhook",
        "operationId": "testWebhook",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Test ping delivery result" }
        }
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "post": {
        "summary": "Rotate webhook signing secret",
        "operationId": "rotateWebhookSecret",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "secret": {
                    "type": "string",
                    "description": "Optional new custom secret (minimum 16 characters). If omitted, an HMAC SHA-256 secret is generated automatically.",
                    "example": "my-new-custom-secret-12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Rotated successfully, returning new unmasked secret once" },
          "404": { "description": "Webhook not found" }
        }
      }
    },
    "/report-aggregates/daily": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get raw daily report aggregates",
        "operationId": "getDailyReportAggregates",
        "description": "Returns the stored per-day report rows for a date range, exactly as the platform keeps them: revenue by category, cost of sales, taxes, payments by method, invoice counts, customers and per-technician stats for each shop-local day. Use it when you need to build your own totals; the other /report-aggregates endpoints are summaries built from these rows. Days with no activity have no row and are omitted. There is no pagination: every row in the range comes back in one response. Both dates are required. Dates are shop-local calendar days (the shop's time zone from Settings; America/Chicago if none is set), written YYYY-MM-DD and inclusive at both ends. Validation: each date must be a real calendar day in YYYY-MM-DD form, must fall between 2000-01-01 and 2100-12-31, and startDate must be on or before endDate. Freshness (cached mode): the figures come from stored per-day rows that are updated as invoices, counter sales and payments change, and an overnight job (07:00 UTC, covering the last 45 days) recomputes them to correct any drift. This endpoint does not add a live calculation for today: today's numbers are whatever the stored row holds, so use mode=live to force a fresh recompute. All money fields end in Cents and are integer cents. Each row's technicianStats omits commissionCents and commissionRatePercent unless the caller holds reports:profit or attendance:financials.",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": true,
            "description": "First day of the range (inclusive), shop-local YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": true,
            "description": "Last day of the range (inclusive), shop-local YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stored daily rows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyAggregatesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Either an invalid date range (error 'Invalid date range' with a message) or a missing parameter (error 'startDate and endDate are required', no message).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "startDate and endDate are required"
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedResponse"
                },
                "example": {
                  "error": "PERMISSION_DENIED",
                  "message": "You do not have permission for reports:operational",
                  "missingPermissions": [
                    "reports:operational"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Internal server error",
                  "message": "An unexpected error occurred"
                }
              }
            }
          }
        },
        "x-permission": "reports:operational",
        "x-money-units": "cents everywhere (every money field is an integer *Cents field; paymentsByMethod values are cents).",
        "x-read-only-key": "with-includePayData"
      }
    },
    "/report-aggregates/sales-summary": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get sales summary",
        "operationId": "getSalesSummaryAggregate",
        "description": "Answers 'how much did the shop invoice and collect over this period, and where did it come from?' Returns revenue split by labor, parts, tires, subcontracts, shop supplies, fees, EPA and service items, with discounts, tax and card surcharge, for all invoices and for fully paid invoices only, plus payments received (by method), unique customers, average repair order, counter-sale revenue, and daily trend series. Work orders and counter sales are both included. Invoices count on their invoiced date and payments on the date received. Dates are shop-local calendar days (the shop's time zone from Settings; America/Chicago if none is set), written YYYY-MM-DD and inclusive at both ends. Validation: each date must be a real calendar day in YYYY-MM-DD form, must fall between 2000-01-01 and 2100-12-31, and startDate must be on or before endDate. When omitted, startDate defaults to the first day of the current month and endDate to today, both in shop time. Freshness (cached mode): the figures come from stored per-day rows that are updated as invoices, counter sales and payments change, and an overnight job (07:00 UTC, covering the last 45 days) recomputes them to correct any drift. This endpoint does not add a live calculation for today: today's numbers are whatever the stored row holds, so use mode=live to force a fresh recompute. Money fields are DOLLARS (decimal numbers), not cents; they are cents divided by 100 and not rounded, so round to 2 decimals for display. No cursor pagination: trendData is limited to the last 30 days of the range (trendDataTruncated says when it was clipped) and trendDaily to 3000 days (trendDailyTruncated).",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "description": "First day of the range (inclusive), shop-local YYYY-MM-DD. Defaults to the first day of the current month in shop time.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "description": "Last day of the range (inclusive), shop-local YYYY-MM-DD. Defaults to today in shop time.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "`cached` (default) reads the stored per-day aggregates. `live` recomputes from raw invoices and payments for the range without writing anything; it is slower (its payment lookup reads the shop's whole payment history, whatever the range). Any other value is treated as `cached`.",
            "schema": {
              "type": "string",
              "enum": [
                "cached",
                "live"
              ],
              "default": "cached"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sales summary.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesSummaryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid date range. `message` is one of: 'Dates must be real calendar days, written YYYY-MM-DD.', 'Dates must fall between 2000 and 2100.', 'The start date must be on or before the end date.'",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Invalid date range",
                  "message": "The start date must be on or before the end date."
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedResponse"
                },
                "example": {
                  "error": "PERMISSION_DENIED",
                  "message": "You do not have permission for reports:operational",
                  "missingPermissions": [
                    "reports:operational"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Internal server error",
                  "message": "An unexpected error occurred"
                }
              }
            }
          }
        },
        "x-permission": "reports:operational",
        "x-money-units": "dollars for every money field (allInvoices, paidInvoices, payments, trendData, trendDaily, averageRepairOrder). Counts are plain integers. This is the opposite of the integer-cents convention used elsewhere in the API.",
        "x-read-only-key": "allowed"
      }
    },
    "/report-aggregates/payments": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get payments summary",
        "operationId": "getPaymentsSummaryAggregate",
        "description": "Answers 'how much money came in over this period, by what method, and on which days?' Returns total payments received, the number of payment transactions, totals by payment method, and a per-day list. Amounts are net of refunds and voided payments; work-order and counter-sale payments are both included, each on the day it was received. Dates are shop-local calendar days (the shop's time zone from Settings; America/Chicago if none is set), written YYYY-MM-DD and inclusive at both ends. Validation: each date must be a real calendar day in YYYY-MM-DD form, must fall between 2000-01-01 and 2100-12-31, and startDate must be on or before endDate. When omitted, startDate defaults to the first day of the current month and endDate to today, both in shop time. Freshness (cached mode): the figures come from stored per-day rows that are updated as invoices, counter sales and payments change, and an overnight job (07:00 UTC, covering the last 45 days) recomputes them to correct any drift. This endpoint does not add a live calculation for today: today's numbers are whatever the stored row holds, so use mode=live to force a fresh recompute. Money fields are DOLLARS (decimal numbers), not cents. dailyTotals lists only days that have a stored row (no zero-fill).",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "description": "First day of the range (inclusive), shop-local YYYY-MM-DD. Defaults to the first day of the current month in shop time.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "description": "Last day of the range (inclusive), shop-local YYYY-MM-DD. Defaults to today in shop time.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "`cached` (default) reads the stored per-day aggregates. `live` recomputes from raw invoices and payments for the range without writing anything; it is slower (its payment lookup reads the shop's whole payment history, whatever the range). Any other value is treated as `cached`.",
            "schema": {
              "type": "string",
              "enum": [
                "cached",
                "live"
              ],
              "default": "cached"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payments summary.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentsSummaryResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid date range. `message` is one of: 'Dates must be real calendar days, written YYYY-MM-DD.', 'Dates must fall between 2000 and 2100.', 'The start date must be on or before the end date.'",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Invalid date range",
                  "message": "The start date must be on or before the end date."
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedResponse"
                },
                "example": {
                  "error": "PERMISSION_DENIED",
                  "message": "You do not have permission for reports:operational",
                  "missingPermissions": [
                    "reports:operational"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Internal server error",
                  "message": "An unexpected error occurred"
                }
              }
            }
          }
        },
        "x-permission": "reports:operational",
        "x-money-units": "dollars for total, byMethod values and dailyTotals[].total; counts are integers. Not integer cents.",
        "x-read-only-key": "allowed"
      }
    },
    "/report-aggregates/tax-collected": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get sales tax collected",
        "operationId": "getTaxCollectedAggregate",
        "description": "Answers 'how much sales tax did the shop collect, at which rates, and what was taxable versus exempt?' Returns, separately for work orders and for counter sales, taxable sales, tax billed, tax received, outstanding tax, a breakdown per tax rate with a drill-down list of the orders behind each rate, a non-taxable section (including resale-certificate and exempt-organization sales), and a parts / labor / subcontract / other split. basis=accrual (default) reports by invoice date: tax billed, with received and outstanding figures pro-rated by how much of each invoice has been paid. basis=cash reports by payment date: only money actually received in the window, whatever period its invoice belongs to, so nothing is outstanding. Dates are shop-local calendar days (the shop's time zone from Settings; America/Chicago if none is set), written YYYY-MM-DD and inclusive at both ends. Validation: each date must be a real calendar day in YYYY-MM-DD form, must fall between 2000-01-01 and 2100-12-31, and startDate must be on or before endDate. When omitted, startDate defaults to the first day of the current month and endDate to today, both in shop time. The figures come from a per-order tax ledger kept current as invoices and payments change. If the ledger for the requested range looks incomplete (fewer than 95% of the expected orders, or rows in an older format) the request rebuilds it first and sets builtOnFirstView to true; that request is slower, and this GET therefore writes data. This endpoint has no `mode` parameter (a `mode` value is ignored). The orders drill-down is capped at 250 rows per rate tier and for the non-taxable list; ordersTruncated says when it was clipped, and totals are always exact. Order rows include the customer name. Money fields end in Cents and are integer cents; rates are percentages.",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "description": "First day of the range (inclusive), shop-local YYYY-MM-DD. Defaults to the first day of the current month in shop time.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "description": "Last day of the range (inclusive), shop-local YYYY-MM-DD. Defaults to today in shop time.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          },
          {
            "name": "basis",
            "in": "query",
            "required": false,
            "description": "Accounting basis. `accrual` (default) = by invoice date; `cash` = by payment date. Case-insensitive; any other value is treated as `accrual`.",
            "schema": {
              "type": "string",
              "enum": [
                "accrual",
                "cash"
              ],
              "default": "accrual"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tax collected report.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxCollectedResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid date range. `message` is one of: 'Dates must be real calendar days, written YYYY-MM-DD.', 'Dates must fall between 2000 and 2100.', 'The start date must be on or before the end date.'",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Invalid date range",
                  "message": "The start date must be on or before the end date."
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedResponse"
                },
                "example": {
                  "error": "PERMISSION_DENIED",
                  "message": "You do not have permission for reports:operational",
                  "missingPermissions": [
                    "reports:operational"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Internal server error",
                  "message": "An unexpected error occurred"
                }
              }
            }
          }
        },
        "x-permission": "reports:operational",
        "x-money-units": "cents everywhere (*Cents fields, integers). Percent fields (taxRatePercent, effectiveTaxRatePercent) are percentages, not fractions. No dollar fields.",
        "x-read-only-key": "allowed"
      }
    },
    "/report-aggregates/commission": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get technician commission report",
        "operationId": "getCommissionReportAggregate",
        "description": "Answers 'what did each technician bill and earn in commission over this period?' Returns per technician the billed labor hours, labor revenue, jobs completed, commission rate and commission earned, plus shop totals, sorted by commission (highest first). Commission is taken from what was stored on each day's invoices at the time (using the technician's commission rate then); if a technician has a rate and labor revenue but stored commission of 0, it is recomputed as revenue times rate. Labor discounts do not reduce commission. Dates are shop-local calendar days (the shop's time zone from Settings; America/Chicago if none is set), written YYYY-MM-DD and inclusive at both ends. Validation: each date must be a real calendar day in YYYY-MM-DD form, must fall between 2000-01-01 and 2100-12-31, and startDate must be on or before endDate. When omitted, startDate defaults to the first day of the current month and endDate to today, both in shop time. Freshness (cached mode): the figures come from stored per-day rows that are updated as invoices, counter sales and payments change, and an overnight job (07:00 UTC, covering the last 45 days) recomputes them to correct any drift. This endpoint does not add a live calculation for today: today's numbers are whatever the stored row holds, so use mode=live to force a fresh recompute. Money fields are DOLLARS (decimal numbers), not cents; they are re-derived from cents with floating-point arithmetic, so round to 2 decimals for display. Rates are percentages. A mechanicId that matches nobody returns an empty list and zero totals, not a 404. This is pay data: callers who hold only reports:operational get 403.",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "description": "First day of the range (inclusive), shop-local YYYY-MM-DD. Defaults to the first day of the current month in shop time.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "description": "Last day of the range (inclusive), shop-local YYYY-MM-DD. Defaults to today in shop time.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
              "minLength": 10,
              "maxLength": 10
            }
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "`cached` (default) reads the stored per-day aggregates. `live` recomputes from raw invoices and payments for the range without writing anything; it is slower (its payment lookup reads the shop's whole payment history, whatever the range). Any other value is treated as `cached`.",
            "schema": {
              "type": "string",
              "enum": [
                "cached",
                "live"
              ],
              "default": "cached"
            }
          },
          {
            "name": "mechanicId",
            "in": "query",
            "required": false,
            "description": "Restrict the report to one technician (user id, exact match).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Commission report.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommissionReportResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid date range. `message` is one of: 'Dates must be real calendar days, written YYYY-MM-DD.', 'Dates must fall between 2000 and 2100.', 'The start date must be on or before the end date.'",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Invalid date range",
                  "message": "The start date must be on or before the end date."
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedResponse"
                },
                "example": {
                  "error": "PERMISSION_DENIED",
                  "message": "You do not have permission for reports:operational",
                  "missingPermissions": [
                    "reports:operational"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Internal server error",
                  "message": "An unexpected error occurred"
                }
              }
            }
          }
        },
        "x-permission": "reports:profit or attendance:financials",
        "x-money-units": "dollars for laborRevenue, commission, totalLaborRevenue, totalCommission; commissionRatePercent and averageCommissionRate are percentages; hours are decimal hours. Not integer cents.",
        "x-read-only-key": "with-includePayData"
      }
    },
    "/report-aggregates/part-usage": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get part usage totals",
        "operationId": "getPartUsageAggregate",
        "description": "Answers 'which parts does the shop actually use, how many, and when was each last used?' Returns one entry per part with the quantity used on invoiced work orders over the last 180 days and over all recorded history, the latest unit cost, and the last-used date; it feeds inventory-health and parts-analytics reports. Parts are keyed by part number (or description when there is no part number). Only part lines on invoiced work orders count: tire and shop-supply lines and counter sales are not in these totals. Takes no date parameters. If startDate or endDate are sent they are validated by the shared date check (and can produce a 400) but are otherwise ignored. The totals are rebuilt once a night from a per-invoice usage ledger (the same 07:00 UTC job as the daily aggregates), so today's invoices do not appear until the next rebuild; updatedAt shows when the newest rows were written. There is no pagination and no limit: every part is returned in one response, so the payload grows with the size of the shop's parts history. totalCostCents is a unit cost in integer cents, not a total.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Part usage totals.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartUsageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid date range. `message` is one of: 'Dates must be real calendar days, written YYYY-MM-DD.', 'Dates must fall between 2000 and 2100.', 'The start date must be on or before the end date.'",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Invalid date range",
                  "message": "The start date must be on or before the end date."
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedResponse"
                },
                "example": {
                  "error": "PERMISSION_DENIED",
                  "message": "You do not have permission for reports:operational",
                  "missingPermissions": [
                    "reports:operational"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Internal server error",
                  "message": "An unexpected error occurred"
                }
              }
            }
          }
        },
        "x-permission": "reports:operational",
        "x-money-units": "cents (totalCostCents, integer). It is a per-unit cost despite the name. Quantities are plain numbers.",
        "x-read-only-key": "allowed"
      }
    },
    "/digests": {
      "get": {
        "tags": [
          "Digests"
        ],
        "summary": "List daily or weekly digests",
        "operationId": "listDigests",
        "description": "Lists the shop's AI morning briefings, newest first, without the full text: headline, date, how it was produced, delivery status and any thumbs rating. A daily digest covers the previous completed business day in the shop's time zone and a weekly digest covers the last completed Monday-to-Sunday week (dated by its Monday). Digests exist only for shops that have the feature switched on: an hourly job writes one after the shop's send hour (5-9 am shop time, default 6), so a shop that never enabled it gets an empty list. Each digest is created once and not updated as the day goes on (regenerating overwrites it). Admin role required; API keys carry it. Pagination: none. The response holds the most recent `limit` digests only (1-60, default 30); there is no cursor and older digests cannot be reached through this endpoint once they fall outside the newest 60. Fetch a specific older one with GET /digests/{date}.",
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "`weekly` selects the weekly digests (keyed by the Monday of the covered week). Any other value, or omitting it, selects daily digests.",
            "schema": {
              "type": "string",
              "enum": [
                "daily",
                "weekly"
              ],
              "default": "daily"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many digests to return, newest first. Clamped to 1-60; a missing, non-numeric or 0 value gives the default of 30.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 60,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Digest history.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigestListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Caller's tenant could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Unauthorized"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not an admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Digest access requires the admin role"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Digest request failed"
                }
              }
            }
          }
        },
        "x-permission": "shop admin role (API keys qualify)",
        "x-money-units": "No money fields on this endpoint.",
        "x-read-only-key": "allowed"
      }
    },
    "/digests/{date}": {
      "get": {
        "tags": [
          "Digests"
        ],
        "summary": "Get one digest",
        "operationId": "getDigest",
        "description": "Returns one full digest: the written briefing (headline, summary, bullets, wins, concerns, things to watch, recommended actions, callouts) and the data snapshot it was built from (revenue, labor, parts, payments, gross profit, open work, receivables and so on, each with comparisons to yesterday, last week or the prior four weeks). Every figure in the narrative is copied from a pre-formatted `display` string in the snapshot; the model never computes numbers, and if validation fails a deterministic template is used (renderMode = fallback). Money in the snapshot is integer cents, each with a matching display string. Keys inside narrative and snapshot are snake_case. For daily digests {date} is the covered day. For weekly digests (period=weekly) {date} must be the Monday of the covered week; any other date returns 404 because the lookup is by exact key. {date} must match YYYY-MM-DD; it is not checked for being a real calendar day, so an impossible date such as 2026-02-31 simply returns 404. A digest that does not exist, or that belongs to another shop, returns 404. Admin role required; API keys carry it. The digest is a fixed record created once; it does not change as the day goes on.",
        "parameters": [
          {
            "name": "date",
            "in": "path",
            "required": true,
            "description": "Business date, YYYY-MM-DD. Daily: the covered day. Weekly: the Monday of the covered week.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "`weekly` selects the weekly digests (keyed by the Monday of the covered week). Any other value, or omitting it, selects daily digests.",
            "schema": {
              "type": "string",
              "enum": [
                "daily",
                "weekly"
              ],
              "default": "daily"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The digest.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigestDetail"
                }
              }
            }
          },
          "401": {
            "description": "Caller's tenant could not be resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Unauthorized"
                }
              }
            }
          },
          "403": {
            "description": "Caller is not an admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Digest access requires the admin role"
                }
              }
            }
          },
          "404": {
            "description": "No digest for that date and period (also returned for a path that is not a YYYY-MM-DD date).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Not found"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Digest request failed"
                }
              }
            }
          }
        },
        "x-permission": "shop admin role (API keys qualify)",
        "x-money-units": "cents (integer *cents fields inside snapshot) plus pre-formatted *_display strings in US dollars with thousands separators (e.g. $4,832.50). No dollar-number fields.",
        "x-read-only-key": "allowed"
      }
    },
    "/dashboard/trend-aggregates": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "summary": "Get daily trend aggregates",
        "operationId": "getDashboardTrendAggregates",
        "description": "Answers 'how did invoicing and payments trend day by day over this range?' Returns one entry per shop-local day that has a stored aggregate: invoice count and revenue (total, labor, parts, tires, counter sales), the same for fully paid invoices, payments received, unique customers, and per-technician stats. It reads the same stored per-day rows as /report-aggregates/daily, converted for charting. Both dates are required. Unlike the /report-aggregates endpoints this one does NOT run the shared date validation: dates are not checked for format or range, startDate after endDate is not rejected up front, and the 2000-2100 bounds do not apply. Send real YYYY-MM-DD dates with startDate <= endDate. Freshness: reads stored daily rows, which are updated as invoices and payments change and recomputed by the overnight job (07:00 UTC, last 45 days); there is no live recalculation here, and there is no `period` parameter. No pagination: the endpoint issues a single database query and does not follow a continuation key, so a very wide range could be cut off at the first ~1 MB of rows with no truncated flag. Keep ranges to a few months. Money units are mixed: all top-level revenue and payment fields are DOLLARS (decimal numbers), but money inside technicianStats (laborRevenueCents, commissionCents) is still integer CENTS. technicianStats omits commissionCents and commissionRatePercent unless the caller holds reports:profit or attendance:financials.",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": true,
            "description": "First day of the range (inclusive), shop-local YYYY-MM-DD. Not validated by this endpoint.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": true,
            "description": "Last day of the range (inclusive), shop-local YYYY-MM-DD. Not validated by this endpoint.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Daily trend rows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardTrendAggregatesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Either date is missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "startDate and endDate query parameters are required (YYYY-MM-DD)"
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks the required permission.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedResponse"
                },
                "example": {
                  "error": "PERMISSION_DENIED",
                  "message": "You do not have permission for dashboard:read",
                  "missingPermissions": [
                    "dashboard:read"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Query failed (for example startDate after endDate).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Failed to get trend aggregates"
                }
              }
            }
          }
        },
        "x-permission": "dashboard:read",
        "x-money-units": "MIXED: dollars for totalRevenue, laborRevenue, partsRevenue, tiresRevenue, paid*, salesOrderRevenue, paymentTotal; integer cents for technicianStats[*].laborRevenueCents and commissionCents; commissionRatePercent is a percentage; counts are integers.",
        "x-read-only-key": "with-includePayData"
      }
    },
    "/dashboard/metrics": {
      "get": {
        "tags": [
          "Dashboard"
        ],
        "summary": "Get dashboard metrics",
        "operationId": "getDashboardMetrics",
        "description": "The numbers behind the shop dashboard: revenue, average job, payments received, gross profit and margin, technician utilization, a day-by-day trend, customers and vehicles served, all for a date range and compared with the previous period of the same length; plus right-now shop-floor counts (open jobs, vehicles in the shop, overdue, delayed, stale, waiting for parts), unpaid invoices, the top customers and invoices owing money, collection health, and low-stock part counts. Each group has its own freshness, and `freshness` in the response says how old each one is. Period figures (revenue, payments, profit, utilization, trend, served counts) come from the stored per-day rows, kept current as invoices and payments change and recomputed overnight; there is no live recalculation, and `isStale` is always false. Floor counters are updated as work orders change and recounted hourly (:10 past the hour). Unpaid totals are updated as invoices change and re-anchored nightly. paymentHealth and collections come from last night's receivables snapshot and cover ALL outstanding receivables, not just the range. Parts counts come from the latest inventory snapshot. Date range: pass BOTH startDate and endDate (YYYY-MM-DD, shop-local, inclusive) for a custom range. If either is missing or malformed, or startDate is after endDate, the range is silently replaced by the current month to date; there is no 400 for that. Calendar-impossible dates are not rejected either (2026-02-31 is accepted and rolls over). The only range error is more than 400 days (400 'Date range too long'). The previous period is the same number of days immediately before startDate. The shop's time zone is NOT read from settings here; it comes from the `timezone` parameter (default America/Chicago) and only decides what 'today' is for the default range. The stored rows themselves are already bucketed by the shop's own time zone. If the shop's history has not been backfilled (stored rows start after its first invoice) the response has building = true and metrics = null. Money units are mixed: every metric is DOLLARS (decimal numbers), except trendDaily.days[*], which is integer CENTS (fields ending in Cents). Tax: periodRevenue, avgPerJob, counterRevenue and the trend's invoicedCents include sales tax; grossProfit.revenue excludes it. The other query parameters you may see used by the app (recalculate) are ignored.",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "description": "First day of a custom range (inclusive), shop-local YYYY-MM-DD. Used only together with endDate; otherwise ignored. Format-checked only, not checked for being a real calendar day.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "description": "Last day of a custom range (inclusive), shop-local YYYY-MM-DD. Used only together with startDate; must be on or after it or both are ignored. The range may span at most 400 days or the request fails with 400.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "IANA time zone name used to decide today's date for the default (month-to-date) range, and echoed in trendDaily.timezone. Default America/Chicago. Not validated: an unknown name silently falls back to UTC for the day calculation. Send the shop's time zone.",
            "schema": {
              "type": "string",
              "default": "America/Chicago",
              "examples": [
                "America/Chicago"
              ]
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Echoed back as `period` in the response (default 'month'). It does not change which dates are used; use startDate and endDate.",
            "schema": {
              "type": "string",
              "default": "month"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Dashboard metrics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardMetricsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Range longer than 400 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Date range too long"
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks dashboard:read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedResponse"
                },
                "example": {
                  "error": "PERMISSION_DENIED",
                  "message": "You do not have permission for dashboard:read",
                  "missingPermissions": [
                    "dashboard:read"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "Unexpected error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBody"
                },
                "example": {
                  "error": "Failed to get dashboard metrics"
                }
              }
            }
          }
        },
        "x-permission": "dashboard:read",
        "x-money-units": "MIXED. Every metric is DOLLARS (decimal numbers, Math.round(cents)/100): periodRevenue, avgPerJob, prevPeriodRevenue, counterRevenue, paymentsReceived, grossProfit.*, unpaidInvoicesAmount, techUtilization.effectiveLaborRate (dollars per hour), paymentHealth.total*, collections.*. EXCEPTION: trendDaily.days[*].*Cents are integer CENTS. Percent fields (revenuePctChange, grossMarginPct, utilizationPct, collectionRate...) are whole-number percentages.",
        "x-read-only-key": "allowed"
      }
    },
    "/reports/customer-aging": {
      "get": {
        "summary": "Customer aging (accounts receivable) as of a day",
        "description": "Answers: who owes the shop money, and how overdue is it? Returns one row per customer with their unpaid invoice balances split into Current (not yet due), 1-30, 31-60, 61-90 and Over 90 days past due, as the books stood at the end of the chosen day in the shop's time zone.\n\n`mode=asOf` (default) replays invoices and dated payments, so it works for any past day and for today (pass today's date for the current picture); `generatedAt` is the request time. `mode=snapshot` returns the end-of-day row stored by the scheduled snapshot job; if no snapshot was stored for that day you get HTTP 200 with `rows: []` and `meta.snapshotFound=false` (not an error). Use `GET /reports/customer-aging/snapshots` to see which days exist.\n\nAn invoice is due 30 days after its invoice date unless the work order has its own due date. Only invoiced work orders that have a customer id are included; counter sales and invoices without a customer are not read. UNITS: every amount in `rows` is DOLLARS (decimal), but `meta.untraceablePaidCents` is cents.",
        "operationId": "getCustomerAging",
        "tags": [
          "Reports"
        ],
        "parameters": [
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "description": "`asOf` replays history; `snapshot` reads the stored end-of-day row. Any value other than `snapshot` is treated as `asOf`.",
            "schema": {
              "type": "string",
              "enum": [
                "asOf",
                "snapshot"
              ],
              "default": "asOf"
            }
          },
          {
            "name": "asOf",
            "in": "query",
            "required": true,
            "description": "Shop-local day, `YYYY-MM-DD`. Required. Must not be later than today in the shop's time zone.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aging rows for the requested day.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAgingResponse"
                }
              }
            }
          },
          "400": {
            "description": "`{\"error\":\"asOf must be a YYYY-MM-DD date\"}` (missing/malformed) or `{\"error\":\"asOf cannot be in the future\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The caller's role lacks `reports:operational`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Body is `{\"error\": \"Failed to load historical aging\"}`; internal detail is logged, not returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          }
        },
        "x-permission": "reports:operational",
        "x-read-only-key": "allowed"
      }
    },
    "/reports/customer-aging/snapshots": {
      "get": {
        "summary": "List days that have a stored aging snapshot",
        "description": "Answers: for which days can I read the stored (audit-grade) receivables snapshot? Returns the dates, newest first. Use one of them as `asOf` with `mode=snapshot` on `GET /reports/customer-aging`.",
        "operationId": "listCustomerAgingSnapshots",
        "tags": [
          "Reports"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Dates with a snapshot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerAgingSnapshotList"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The caller's role lacks `reports:operational`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Body is `{\"error\": \"Failed to list snapshots\"}`; internal detail is logged, not returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          }
        },
        "x-permission": "reports:operational",
        "x-read-only-key": "allowed"
      }
    },
    "/reports/weekly-trend": {
      "get": {
        "summary": "Week-over-week revenue and profit trend",
        "description": "Answers: how is the shop trending week to week? Returns up to `weeks` weekly data points (Monday-Sunday in the shop's time zone), oldest to newest: revenue, labor and parts revenue and profit, labor hours, jobs, customers and invoice count.\n\nThese are pre-computed rollups, not live. The nightly rollup (00:00 UTC) recomputes the current and the previous week; older weeks only change on a backfill. So the current week reflects the last nightly run, not this minute.\n\nUNITS: all money is integer cents. (A stale code comment says dollars; the payload is cents.) `revenueCents` includes tax; `partsRevenueCents`/`partsProfitCents` include tires.",
        "operationId": "getWeeklyTrendReport",
        "tags": [
          "Reports"
        ],
        "parameters": [
          {
            "name": "weeks",
            "in": "query",
            "required": false,
            "description": "How many most-recent weeks to return. Values above 52 are clamped to 52, below 1 to 1, and non-numeric input falls back to 12.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 52,
              "default": 12
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Weekly data points.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WeeklyTrendResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The caller's role lacks `reports:operational`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "500": {
            "description": "Server error. Body is `{\"error\": \"Failed to get weekly trend\"}`; internal detail is logged, not returned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          }
        },
        "x-permission": "reports:operational",
        "x-read-only-key": "allowed"
      }
    },
    "/vendors/ap-report": {
      "get": {
        "summary": "Vendor accounts payable report (what the shop owes vendors)",
        "description": "Answers: how much does the shop owe its vendors, how overdue is it, and what was bought, returned and held in core deposits? One call returns vendor invoices with net-30 aging as of TODAY (shop-local), purchase orders, part returns, core-deposit lines and core write-offs.\n\nComputed live on every request from purchase orders, ad-hoc vendor invoices, vendors and core write-offs. A PO counts as an invoice only if it has a vendor invoice number. All money is integer cents.\n\nLists are newest-first and cut at 5000 rows each; `truncated` is an ARRAY of the source names that hit a cap (empty = complete).",
        "operationId": "getVendorApReport",
        "tags": [
          "Vendors"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Derived AP rows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorApReport"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The caller's role lacks `vendors:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error: `{\"error\":\"Internal Server Error\",\"message\":\"An unexpected error occurred\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorWithMessage"
                }
              }
            }
          }
        },
        "x-permission": "vendors:read",
        "x-read-only-key": "allowed"
      }
    },
    "/inventory/parts-purchasing-report": {
      "get": {
        "summary": "Parts purchasing ledger (opening, purchases, usage, closing)",
        "description": "Answers: what did the shop buy, use and hold in a period, and how did inventory value move? Default response is a shop-wide summary (opening value, purchases, usage with revenue and profit, reserved/held change, closing value, a reconciliation residual and cost changes) plus one ledger row per part, tire, fluid or shop item that had activity.\n\nDates are shop-local days (inclusive both ends, shop time zone default America/Chicago). All money is integer cents; quantities are units.\n\nThe same route has drill-down modes selected by query parameters (precedence: `view=daily`, then `partId`, then `bucket`; otherwise the list): `partId` returns that part's raw transactions, `bucket` returns transactions across parts, `view=daily` returns a part x day pivot. The detail modes are paginated with `page`/`limit` and report `hasMore`.\n\nOpening/closing come from end-of-day inventory snapshots; where a snapshot is missing the value is null, or live (flagged `openingIsLive`/`closingIsLive`) when the window touches today.\n\nCost, price and profit are returned to any caller that passes the read gate; there is no per-field cost masking.",
        "operationId": "getPartsPurchasingReport",
        "tags": [
          "Inventory"
        ],
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": true,
            "description": "First shop-local day, `YYYY-MM-DD`. Required (presence only is validated; format is not).",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": true,
            "description": "Last shop-local day (inclusive), `YYYY-MM-DD`. Required.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Case-insensitive substring match on part number or part name (list, bucket and daily modes).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "List mode: single category, exact case-insensitive match against each row's `partCategory`. Bucket/daily modes: comma-separated exact, case-sensitive values.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "partId",
            "in": "query",
            "required": false,
            "description": "Return this item's raw transactions instead of the list (an inventory part id or a material id).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "bucket",
            "in": "query",
            "required": false,
            "description": "Return transactions across parts counted in this bucket.",
            "schema": {
              "type": "string",
              "enum": [
                "inbound",
                "outbound",
                "reserved"
              ]
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "`daily` returns the part x shop-day pivot.",
            "schema": {
              "type": "string",
              "enum": [
                "daily"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Detail modes only (`partId`/`bucket`). 1-based.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Detail modes only (`partId`/`bucket`). Page size, capped at 500.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 200
            }
          },
          {
            "name": "vendor",
            "in": "query",
            "required": false,
            "description": "Bucket/daily modes only. Comma-separated vendor names (case-insensitive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "types",
            "in": "query",
            "required": false,
            "description": "Bucket/daily modes only. Comma-separated transaction types.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sources",
            "in": "query",
            "required": false,
            "description": "Bucket/daily modes only. Comma-separated reference types (work_order, purchase_order, manual, ...).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Shape depends on the mode query parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PartsPurchasingReport"
                    },
                    {
                      "$ref": "#/components/schemas/PartsPurchasingPartDetail"
                    },
                    {
                      "$ref": "#/components/schemas/PartsPurchasingBucketDetail"
                    },
                    {
                      "$ref": "#/components/schemas/PartsPurchasingDaily"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`{\"error\":\"startDate and endDate are required (YYYY-MM-DD)\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The caller's role lacks `inventory:read (or parts:read)`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error: `{\"error\":\"Internal Server Error\",\"message\":\"An unexpected error occurred\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorWithMessage"
                }
              }
            }
          }
        },
        "x-permission": "inventory:read OR parts:read",
        "x-read-only-key": "allowed"
      }
    },
    "/inventory/parts-activities": {
      "get": {
        "summary": "Parts activity log (every stock movement and part edit in a period)",
        "description": "Answers: who changed inventory, when, and why? Lists quantity movements (purchases received, adjustments, reservations, usage on work orders and counter sales, returns) and part edit/create events over a date range, newest first, with KPI stats, filter facets and the same opening/closing inventory cards as the purchasing report.\n\nPass `groupBy` to get subtotalled groups instead of rows (not paginated), or `view=lifecycle` to collapse each part's events per order. Dates are shop-local days (inclusive). All money is integer cents.\n\nPagination is `page`/`limit` (not a cursor). Each source stream is read up to 5000 rows; when that cap is hit `truncated` is true and the list and stats are partial.",
        "operationId": "listPartsActivities",
        "tags": [
          "Inventory"
        ],
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": true,
            "description": "First shop-local day, `YYYY-MM-DD`. Required.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": true,
            "description": "Last shop-local day (inclusive). Required.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "partId",
            "in": "query",
            "required": false,
            "description": "Single-part view (part or material id). Looks that item up directly.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "activityType",
            "in": "query",
            "required": false,
            "description": "Comma-separated activity types (case-insensitive). Valid values appear in `facets.types`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "description": "Only events performed by this user id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "Comma-separated reference types, e.g. work_order, manual, purchase_order, ai_upload, release_queue (case-insensitive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "vendor",
            "in": "query",
            "required": false,
            "description": "Comma-separated vendor names (case-insensitive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Comma-separated part categories (case-insensitive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "invoiceNumber",
            "in": "query",
            "required": false,
            "description": "Exact vendor invoice number.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "poNumber",
            "in": "query",
            "required": false,
            "description": "Exact PO number.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Case-insensitive substring over part number/name, work order number, customer, invoice #, PO #, vendor and user name.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "1-based page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, clamped to 1-200.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "required": false,
            "description": "Return subtotalled groups instead of rows. Unknown values are ignored.",
            "schema": {
              "type": "string",
              "enum": [
                "vendor",
                "category",
                "activityType",
                "source",
                "performedBy",
                "invoice",
                "po"
              ]
            }
          },
          {
            "name": "thenBy",
            "in": "query",
            "required": false,
            "description": "Second grouping level (with `groupBy`).",
            "schema": {
              "type": "string",
              "enum": [
                "vendor",
                "category",
                "activityType",
                "source",
                "performedBy",
                "invoice",
                "po"
              ]
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "`lifecycle`: one row per part per order, with the events nested in `children`. Ignored with `groupBy`.",
            "schema": {
              "type": "string",
              "enum": [
                "lifecycle"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rows (default) or groups (when `groupBy` is set).",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/PartsActivitiesResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PartsActivitiesGroupedResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`{\"error\":\"startDate and endDate are required (YYYY-MM-DD)\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The caller's role lacks `inventory:read (or parts:read)`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error: `{\"error\":\"Internal Server Error\",\"message\":\"An unexpected error occurred\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorWithMessage"
                }
              }
            }
          }
        },
        "x-permission": "inventory:read OR parts:read",
        "x-read-only-key": "allowed"
      }
    },
    "/shop-financials/months": {
      "get": {
        "summary": "List months that have shop financials",
        "description": "Answers: which months have overhead/expense and income bookkeeping, and what are their totals? Returns one record per month (newest first) with total expenses, total income, net, and entry counts. These are the shop-entered Shop Financials figures (rent, utilities, insurance, payroll as booked, etc.), not work-order revenue.\n\nAll money is integer cents. Totals are stored on the month record and updated whenever an entry changes.",
        "operationId": "listShopFinancialMonths",
        "tags": [
          "Shop Financials"
        ],
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Only months in this calendar year (e.g. 2026). A non-numeric value is ignored (no filter).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Months, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShopFinancialMonthList"
                }
              }
            }
          },
          "401": {
            "description": "`{\"error\":\"Unauthorized\"}` when the tenant cannot be resolved from the authorizer context.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "403": {
            "description": "`{\"error\":\"You do not have permission to view shop financials.\"}` - NOTE this route does not use the PERMISSION_DENIED body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "500": {
            "description": "`{\"error\":\"Something went wrong loading shop financials.\"}` (or `Could not complete the accounting request.` from the accounting router).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          }
        },
        "x-permission": "reports:profit",
        "x-read-only-key": "allowed"
      }
    },
    "/shop-financials/months/{month}": {
      "get": {
        "summary": "One month of shop financials with all expense and income lines",
        "description": "Answers: what overhead did the shop book in this month and what other income did it record? Returns the month record plus every expense line (vendor, category, amount, paid status, linked bank transaction), income line (with linked counter-sale status) and recorded payment/receipt transaction. These are shop-entered or bank-promoted entries - not derived from work orders.\n\nAll money is integer cents. The month must be `YYYY-MM`; a month that was never created returns 404.",
        "operationId": "getShopFinancialMonth",
        "tags": [
          "Shop Financials"
        ],
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "Month key, `YYYY-MM`. Any other shape does not match this route and returns 404 'Shop Financials endpoint not found'.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}$",
              "example": "2026-09"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Month with its lines.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShopFinancialMonthDetail"
                }
              }
            }
          },
          "401": {
            "description": "`{\"error\":\"Unauthorized\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "403": {
            "description": "`{\"error\":\"You do not have permission to view shop financials.\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "404": {
            "description": "`{\"error\":\"Month not found\"}` (no such month for this shop) or `{\"error\":\"Shop Financials endpoint not found\",\"details\":{path,method}}` (malformed month).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "500": {
            "description": "`{\"error\":\"Something went wrong loading shop financials.\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          }
        },
        "x-permission": "reports:profit",
        "x-read-only-key": "allowed"
      }
    },
    "/work-orders/technician-labor-summary": {
      "get": {
        "summary": "Per-technician completed labor hours, revenue and cost",
        "description": "Answers: how many labor hours did each technician complete in this period, what did that labor bill, and what did it cost the shop? Per technician: hours, labor revenue, jobs, hours per day and a line-by-line breakdown. LABOR ONLY (parts are not attributed to technicians).\n\n`basis` decides which date puts a labor line in the period: `labor-completed` (the day the line was completed) or `invoiced` (the day its work order was invoiced). The shop's own setting (Settings > Labor, `billableHoursBasis`) is the default; you may request either value via `basis`. Days are shop-local.\n\nEMPLOYEE PAY DATA: `laborCostCents`, `commissionCents` and `breakdown[].costCents` reveal what the shop pays each technician (hourly cost rate x hours; flat-weekly staff prorated) and their commission. The server removes these fields for callers without `reports:profit` or `attendance:financials`; API keys authenticate as admin and always receive them.\n\nAll money is integer cents; hours are decimal. The read is capped at 5000 work orders; `truncated: true` means totals are partial.",
        "operationId": "getTechnicianLaborSummary",
        "tags": [
          "Technicians & Labor"
        ],
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": true,
            "description": "First shop-local day, `YYYY-MM-DD`. Required (a longer ISO timestamp is accepted: only the first 10 characters are used).",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": true,
            "description": "Last shop-local day (inclusive). Required.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "basis",
            "in": "query",
            "required": false,
            "description": "Which date decides the period. Omitted or any other value falls back to the shop's `billableHoursBasis` setting (default `labor-completed`).",
            "schema": {
              "type": "string",
              "enum": [
                "labor-completed",
                "invoiced"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-technician totals.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TechnicianLaborSummaryResponse"
                }
              }
            }
          },
          "400": {
            "description": "`{\"error\":\"startDate and endDate are required (YYYY-MM-DD)\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The caller's role lacks `workorders:read / workorders:read-all`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error: `{\"error\":\"Internal Server Error\",\"message\":\"An unexpected error occurred\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorWithMessage"
                }
              }
            }
          }
        },
        "x-permission": "workorders:read + reports:operational",
        "x-read-only-key": "with-includePayData"
      }
    },
    "/customers/{customerId}/unpaid-invoices": {
      "get": {
        "summary": "A customer's open (unpaid) invoices",
        "description": "Answers: what does this customer currently owe, invoice by invoice? Lists the customer's invoiced work orders and counter sales that still have a balance, oldest first. Archived invoices that are still unpaid are included. Balances are computed from the Payments table (net of refunds), with declined services excluded, so they match what a statement would show.\n\nMoney is returned twice: integer cents (`*Cents`, canonical) and dollar decimals (`total`, `paid`, `balance`). Dates for `startDate`/`endDate` are shop-local, compared against the invoice date (invoiced date, else created); invoices with no date are included.\n\nIf the customer has more than 1500 open invoices only the 1500 most recent are evaluated and `truncated` is true; narrow with `startDate`/`endDate`. An unknown or other-shop customer id returns 200 with an empty list, not 404.",
        "operationId": "listCustomerUnpaidInvoices",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "description": "Customer id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "description": "Only invoices dated on/after this shop-local day (`YYYY-MM-DD`, inclusive).",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "description": "Only invoices dated on/before this shop-local day (inclusive).",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Open invoices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerUnpaidInvoicesResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The caller's role lacks `customers:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "500": {
            "description": "`{\"error\":\"Failed to list unpaid invoices\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          }
        },
        "x-permission": "customers:read",
        "x-read-only-key": "allowed"
      }
    },
    "/customers/{customerId}/statements": {
      "get": {
        "summary": "Statements created for a customer",
        "description": "Answers: what statements has the shop built for this customer and where do they stand? Each statement bundles several invoices; every read re-resolves the bundled invoices live (total, paid, balance and the payments applied), so numbers are current rather than as-created. Newest first.\n\nMoney is returned as integer cents plus dollar twins (`totalAmount`, `paidAmount`, `totalDue`). `status` is recomputed to `Paid` when nothing is due or `Partial` when something was paid, otherwise the stored status (`Draft` when created). There is no pagination and no truncation flag. Payment rows include card brand/last4, check numbers and bank names.",
        "operationId": "listCustomerStatements",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "description": "Customer id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Statements, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerStatementList"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden: lacks `customers:read`, or the role is explicitly denied `customers:financials`. Body is PERMISSION_DENIED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "`{\"error\":\"Customer not found\"}` - unknown id OR a customer in another shop (cross-tenant reads return 404).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          },
          "500": {
            "description": "`{\"error\":\"Failed to list statements\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          }
        },
        "x-permission": "customers:read",
        "x-read-only-key": "allowed"
      }
    },
    "/payments": {
      "get": {
        "summary": "List payments received (work orders and counter sales)",
        "description": "Answers: what money came in, and when? Returns payment records for the whole shop (work-order invoices and counter sales merged), optionally restricted to a date range. Amounts are integer cents.\n\nPAGING: cursor-based, but with `cursor`/`nextCursor` (opaque base64), NOT `lastEvaluatedKey`. To fetch everything in a period, pass `startDate`+`endDate` and keep passing the returned `nextCursor` until `hasMore` is false. `limit` is a minimum target rather than a hard maximum: pages stop at a database page boundary, so a page can return more than `limit` rows. The payment day used for the date filter is `date`, else `paymentDate`, else `createdAt` (shop-local when `timezone` is given, otherwise the UTC date prefix).\n\nWithout a date range the rows are NOT the newest payments: work-order payments are stored under `PAYMENT#<uuid>`, so the first page is an arbitrary slice. Always pass a date range for reporting.\n\nRows are the stored payment records, including payer details such as Zelle contact and check/bank details, and `createdByName` (the employee who recorded it).",
        "operationId": "listPayments",
        "tags": [
          "Payments"
        ],
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "description": "First day (inclusive), `YYYY-MM-DD`. Compared as a string against the payment day label.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "description": "Last day (inclusive), `YYYY-MM-DD`.",
            "schema": {
              "type": "string",
              "format": "date",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "IANA zone used to turn timestamped payments into a day for the date filter. Without it the UTC date prefix is used, so evening payments can land on the next day.",
            "schema": {
              "type": "string",
              "example": "America/Chicago"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Target number of in-range rows per source (work-order and counter-sale payments) per page; values above 1000 are clamped to 1000, so a page can hold up to 2000 rows. A page may also stop early to stay under the response-size limit. Follow `nextCursor` until it is absent to read the full range.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque cursor from a previous response's `nextCursor`. A malformed cursor is silently ignored and the listing restarts from the beginning (risk of duplicate rows).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of payments.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentListResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden. The caller's role lacks `payments:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "500": {
            "description": "`{\"error\":\"Internal Server Error\"}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimpleError"
                }
              }
            }
          }
        },
        "x-permission": "payments:read",
        "x-read-only-key": "allowed"
      }
    },
    "/inspections/{id}": {
      "get": {
        "tags": [
          "Inspections"
        ],
        "summary": "Get inspection by ID",
        "operationId": "getInspection",
        "x-read-only-key": "allowed",
        "description": "One inspection with its checklist items, photos and notes. Photo and video links are signed and expire, so fetch them promptly and do not store them. A record that does not exist and one that belongs to another shop both return 404.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Inspection ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The inspection",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "inspection": {
                      "type": "object",
                      "description": "The inspection record: status, vehicle and work order links, checklist items with their results, and signed media links."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Inspection not found (or not in this shop)."
          }
        }
      }
    }
  }
}
