{
  "tools": [
    {
      "name": "list_contacts",
      "description": "List contacts with optional pagination and search",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search by name, email, phone, or company"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "first_name",
              "last_name",
              "email",
              "phone",
              "company",
              "type",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. There is no \"name\" field — use first_name or last_name. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "type": {
            "type": "string",
            "enum": [
              "none",
              "customer",
              "lead",
              "former_customer",
              "contractor",
              "partner",
              "vendor",
              "other"
            ],
            "description": "Filter by contact type"
          },
          "owner_id": {
            "type": "string",
            "format": "uuid",
            "description": "Filter by owner user UUID. Use list_users to resolve names."
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "type": "integer",
              "exclusiveMinimum": 0
            },
            "description": "Filter to records carrying ANY of these tag IDs (not all). Use list_tags with the matching taggable_type to resolve tag names to IDs first."
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_contact",
      "description": "Create a new contact",
      "inputSchema": {
        "type": "object",
        "properties": {
          "first_name": {
            "type": "string",
            "description": "First name (required)"
          },
          "last_name": {
            "type": "string",
            "description": "Last name (required)"
          },
          "email": {
            "type": "string",
            "description": "Primary email address"
          },
          "phone": {
            "type": "string",
            "description": "Primary phone number"
          },
          "secondary_email": {
            "type": "string",
            "description": "Secondary email address"
          },
          "secondary_phone": {
            "type": "string",
            "description": "Secondary phone number"
          },
          "company": {
            "type": "string",
            "description": "Company name"
          },
          "company_department": {
            "type": "string",
            "description": "Department within company"
          },
          "company_position": {
            "type": "string",
            "description": "Position/title at company"
          },
          "title": {
            "type": "string",
            "enum": [
              "mr",
              "mrs",
              "miss",
              "ms",
              "dr",
              "prof",
              "rev"
            ],
            "description": "Honorific title"
          },
          "type": {
            "type": "string",
            "enum": [
              "none",
              "customer",
              "lead",
              "former_customer",
              "contractor",
              "partner",
              "vendor",
              "other"
            ],
            "description": "Contact type (default: none)"
          },
          "owner_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the contact owner. Use list_users to resolve names."
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "required": [
          "first_name",
          "last_name"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_contact",
      "description": "Get a single contact by ID with expanded details (properties, activity)",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_contact",
      "description": "Update an existing contact",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact ID"
          },
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "email": {
            "type": "string",
            "description": "Primary email address"
          },
          "phone": {
            "type": "string",
            "description": "Primary phone number"
          },
          "secondary_email": {
            "type": "string",
            "description": "Secondary email address"
          },
          "secondary_phone": {
            "type": "string",
            "description": "Secondary phone number"
          },
          "company": {
            "type": "string",
            "description": "Company name"
          },
          "company_department": {
            "type": "string",
            "description": "Department within company"
          },
          "company_position": {
            "type": "string",
            "description": "Position/title at company"
          },
          "title": {
            "type": "string",
            "enum": [
              "mr",
              "mrs",
              "miss",
              "ms",
              "dr",
              "prof",
              "rev"
            ],
            "description": "Honorific title"
          },
          "type": {
            "type": "string",
            "enum": [
              "none",
              "customer",
              "lead",
              "former_customer",
              "contractor",
              "partner",
              "vendor",
              "other"
            ],
            "description": "Contact type"
          },
          "owner_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the contact owner. Use list_users to resolve names."
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_contact",
      "description": "Delete a client. Their properties, follow-up tasks, notes and saved payment methods cascade away with them. Jobs, quotes and invoices remain but are left without a client. Confirm with the user first, especially when the client has live work — there is no undo.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_properties",
      "description": "List properties (service addresses) across the workspace with optional search by street, city, state, or zip code. Returns linked contact IDs.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "search": {
            "type": "string",
            "description": "Search by street, city, state, or postal code"
          },
          "property_type": {
            "type": "string",
            "enum": [
              "single-family",
              "apartment",
              "complex",
              "townhouse",
              "land",
              "commercial",
              "other"
            ],
            "description": "Filter by property type"
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "property_type",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by"
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_contact_properties",
      "description": "List all properties (service addresses) for a contact",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact ID"
          }
        },
        "required": [
          "contact_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_contact_property",
      "description": "Add a property (service address) to a contact",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact ID"
          },
          "address": {
            "type": "object",
            "properties": {
              "street": {
                "type": "string",
                "description": "Street address line 1"
              },
              "street_2": {
                "type": "string",
                "description": "Street address line 2"
              },
              "city": {
                "type": "string",
                "description": "City"
              },
              "state": {
                "type": "string",
                "description": "State/province"
              },
              "postal_code": {
                "type": "string",
                "description": "Postal/zip code"
              },
              "country": {
                "type": "string",
                "description": "Country"
              }
            },
            "additionalProperties": false,
            "description": "Property address"
          },
          "property_type": {
            "type": "string",
            "enum": [
              "single-family",
              "apartment",
              "complex",
              "townhouse",
              "land",
              "commercial",
              "other"
            ],
            "description": "Property type (default: single-family)"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "tenant",
              "manager",
              "agent",
              "other"
            ],
            "description": "Contact role for this property (default: owner)"
          }
        },
        "required": [
          "contact_id",
          "address"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_contact_property",
      "description": "Update a property for a contact",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Property ID"
          },
          "address": {
            "type": "object",
            "properties": {
              "street": {
                "type": "string",
                "description": "Street address line 1"
              },
              "street_2": {
                "type": "string",
                "description": "Street address line 2"
              },
              "city": {
                "type": "string",
                "description": "City"
              },
              "state": {
                "type": "string",
                "description": "State/province"
              },
              "postal_code": {
                "type": "string",
                "description": "Postal/zip code"
              },
              "country": {
                "type": "string",
                "description": "Country"
              }
            },
            "additionalProperties": false,
            "description": "Property address"
          },
          "property_type": {
            "type": "string",
            "enum": [
              "single-family",
              "apartment",
              "complex",
              "townhouse",
              "land",
              "commercial",
              "other"
            ],
            "description": "Property type"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "tenant",
              "manager",
              "agent",
              "other"
            ],
            "description": "Contact role for this property"
          }
        },
        "required": [
          "contact_id",
          "property_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_contact_property",
      "description": "Delete a property from a contact",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Property ID"
          }
        },
        "required": [
          "contact_id",
          "property_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_contact_tasks",
      "description": "List the follow-up tasks and reminders on a client — things like \"call back Thursday\" or \"annual service due\". Filter by status to see what is still outstanding.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact ID whose tasks to list."
          },
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "open",
                "completed",
                "overdue"
              ]
            },
            "description": "Filter by one or more statuses: open, completed, overdue."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page"
          }
        },
        "required": [
          "contact_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_contact_task",
      "description": "Add a follow-up task or reminder to a client. Use this for anything the user wants to remember about a specific client that is not itself billable work — \"follow up next week\", \"chase the deposit\", \"annual service due in March\". For work that gets done and paid for, create a job instead.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact the task belongs to."
          },
          "title": {
            "type": "string",
            "description": "Short title, e.g. \"Call about deck quote\"."
          },
          "description": {
            "type": "string",
            "description": "Any extra detail."
          },
          "due_date": {
            "type": "string",
            "description": "When it is due, as an ISO timestamp. Reminders fire relative to this, so include a time — \"Thursday\" alone is not enough. Required for a recurring task."
          },
          "assignee_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the team member responsible. Use list_users to resolve a name."
          },
          "reminders_enabled": {
            "type": "boolean",
            "description": "Whether the assignee is notified as the due date approaches. Defaults to FALSE, so a task created without this is a silent to-do that nobody is nudged about. Turn it on when the user says \"remind me\"."
          },
          "recurrence_type": {
            "type": "string",
            "enum": [
              "single",
              "recurring"
            ],
            "description": "Set to 'recurring' for a reminder that repeats (a yearly service check, a monthly courtesy call). Default: 'single'."
          },
          "repeat_frequency": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Interval, used when repeat_frequency_unit is 'custom'."
          },
          "repeat_frequency_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How often it repeats: daily, weekly, monthly, yearly, or custom. Default: weekly."
          },
          "repeat_frequency_unit_custom": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "Unit the custom interval counts in. Only used with repeat_frequency_unit='custom'."
          },
          "repeat_frequency_schedule": {
            "type": "object",
            "properties": {
              "days": {
                "type": "array",
                "items": {
                  "$ref": "#/properties/repeat_frequency"
                },
                "description": "1-7 for weekdays, 1-31 for days of the month."
              },
              "type": {
                "type": "string",
                "enum": [
                  "weekDays",
                  "monthWeekDays",
                  "monthDays"
                ]
              }
            },
            "required": [
              "days",
              "type"
            ],
            "additionalProperties": false,
            "description": "Which days a custom weekly or monthly pattern lands on. Required for those."
          },
          "repeat_duration": {
            "$ref": "#/properties/repeat_frequency",
            "description": "How long it repeats. With repeat_duration_unit='occurrences' this is a count. Required unless it repeats forever."
          },
          "repeat_duration_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How it ends: 'forever', 'occurrences', or a time unit. Default: forever."
          }
        },
        "required": [
          "contact_id",
          "title"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_contact_task",
      "description": "Edit a follow-up task. To mark one done, use complete_contact_task instead — for a repeating reminder, that completes just the one occurrence rather than touching the series.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact the task belongs to."
          },
          "task_id": {
            "$ref": "#/properties/contact_id",
            "description": "Task ID."
          },
          "title": {
            "type": "string",
            "description": "New title."
          },
          "description": {
            "type": "string",
            "description": "New description."
          },
          "due_date": {
            "type": "string",
            "description": "New due date as an ISO timestamp."
          },
          "assignee_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the team member responsible. Use list_users to resolve names."
          },
          "reminders_enabled": {
            "type": "boolean",
            "description": "Whether the assignee is notified as the due date approaches. Defaults to FALSE, so a task created without this is a silent to-do that nobody is nudged about. Turn it on when the user says \"remind me\"."
          },
          "update_scope": {
            "type": "string",
            "enum": [
              "single",
              "all",
              "recreate"
            ],
            "description": "For a repeating reminder: 'single' changes only this one, 'all' applies to future ones too, 'recreate' rebuilds the upcoming series after a pattern change. Ask which the user means. Default: single."
          },
          "recurrence_type": {
            "type": "string",
            "enum": [
              "single",
              "recurring"
            ],
            "description": "Set to 'recurring' for a reminder that repeats (a yearly service check, a monthly courtesy call). Default: 'single'."
          },
          "repeat_frequency": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Interval, used when repeat_frequency_unit is 'custom'."
          },
          "repeat_frequency_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How often it repeats: daily, weekly, monthly, yearly, or custom. Default: weekly."
          },
          "repeat_frequency_unit_custom": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "Unit the custom interval counts in. Only used with repeat_frequency_unit='custom'."
          },
          "repeat_frequency_schedule": {
            "type": "object",
            "properties": {
              "days": {
                "type": "array",
                "items": {
                  "$ref": "#/properties/repeat_frequency"
                },
                "description": "1-7 for weekdays, 1-31 for days of the month."
              },
              "type": {
                "type": "string",
                "enum": [
                  "weekDays",
                  "monthWeekDays",
                  "monthDays"
                ]
              }
            },
            "required": [
              "days",
              "type"
            ],
            "additionalProperties": false,
            "description": "Which days a custom weekly or monthly pattern lands on. Required for those."
          },
          "repeat_duration": {
            "$ref": "#/properties/repeat_frequency",
            "description": "How long it repeats. With repeat_duration_unit='occurrences' this is a count. Required unless it repeats forever."
          },
          "repeat_duration_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How it ends: 'forever', 'occurrences', or a time unit. Default: forever."
          }
        },
        "required": [
          "contact_id",
          "task_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "complete_contact_task",
      "description": "Mark a follow-up task done, or reopen one. For a repeating reminder this affects only the single occurrence, leaving the rest of the series in place.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact the task belongs to."
          },
          "task_id": {
            "$ref": "#/properties/contact_id",
            "description": "Task ID."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "completed",
              "overdue"
            ],
            "description": "completed to mark it done, open to reopen it, overdue to flag it."
          }
        },
        "required": [
          "contact_id",
          "task_id",
          "status"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_contact_task",
      "description": "Delete a follow-up task. To record that it was done rather than remove it, use complete_contact_task — deleting loses the history.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Contact the task belongs to."
          },
          "task_id": {
            "$ref": "#/properties/contact_id",
            "description": "Task ID."
          }
        },
        "required": [
          "contact_id",
          "task_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_equipment",
      "description": "List the company's own equipment — vehicles, trailers, tools and machines the business owns. This is NOT equipment installed at a customer's property.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "active",
                "in_repair",
                "retired",
                "sold"
              ]
            },
            "description": "Filter by status: active, in_repair, retired, sold."
          },
          "search": {
            "type": "string",
            "description": "Search by name, make, model or serial number."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_equipment",
      "description": "Get one piece of company equipment with its details and assignee.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_equipment",
      "description": "Add a piece of company equipment — a truck, trailer, tool or machine the business owns. Leave `name` off and it is derived from year/make/model, falling back to the serial number and then the category. Setting `replacement_date` automatically creates a \"Replace <name>\" reminder task.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name. Omit to derive it from year, make and model."
          },
          "category": {
            "type": "string",
            "enum": [
              "vehicle",
              "trailer",
              "tool",
              "machine",
              "other"
            ],
            "description": "Default: other."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "in_repair",
              "retired",
              "sold"
            ],
            "description": "Default: active."
          },
          "description": {
            "type": "string"
          },
          "make": {
            "type": "string",
            "description": "Manufacturer, e.g. Ford."
          },
          "model": {
            "type": "string",
            "description": "Model, e.g. F-250."
          },
          "year": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Model year."
          },
          "serial_number": {
            "type": "string",
            "description": "Serial or VIN."
          },
          "purchase_date": {
            "type": "string",
            "description": "YYYY-MM-DD."
          },
          "purchase_price": {
            "type": "number"
          },
          "warranty_expiration": {
            "$ref": "#/properties/purchase_date",
            "description": "YYYY-MM-DD."
          },
          "warranty_number": {
            "type": "string"
          },
          "replacement_date": {
            "$ref": "#/properties/purchase_date",
            "description": "When it is due for replacement (YYYY-MM-DD). Setting this creates a reminder task automatically; clearing it removes that task if still open."
          },
          "assignee_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the team member responsible. Use list_users to resolve a name."
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_equipment",
      "description": "Update a piece of company equipment. Send only the fields that change — the server merges them over the existing record, so a status change on its own will not disturb the name or other details.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment ID"
          },
          "name": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "enum": [
              "vehicle",
              "trailer",
              "tool",
              "machine",
              "other"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "in_repair",
              "retired",
              "sold"
            ],
            "description": "active, in_repair, retired or sold."
          },
          "description": {
            "type": "string"
          },
          "make": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "year": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "serial_number": {
            "type": "string"
          },
          "purchase_date": {
            "type": "string",
            "description": "YYYY-MM-DD."
          },
          "purchase_price": {
            "type": "number"
          },
          "warranty_expiration": {
            "$ref": "#/properties/purchase_date",
            "description": "YYYY-MM-DD."
          },
          "warranty_number": {
            "type": "string"
          },
          "replacement_date": {
            "$ref": "#/properties/purchase_date",
            "description": "Changing this moves the automatic replacement reminder task."
          },
          "assignee_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the responsible team member. Use list_users to resolve names."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_equipment",
      "description": "Delete a piece of company equipment, along with its tasks and service log. To take something out of service without losing its history, set status to \"retired\" or \"sold\" instead.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_equipment_tasks",
      "description": "List maintenance tasks on a piece of company equipment — services, inspections, and the automatic replacement reminder.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment ID"
          },
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "open",
                "completed",
                "overdue"
              ]
            },
            "description": "Filter by status: open, completed, overdue."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "equipment_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_equipment_task",
      "description": "Add a maintenance task to a piece of company equipment — an oil change, an inspection, a repair to book. Use recurrence for scheduled servicing that repeats.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment the task belongs to."
          },
          "title": {
            "type": "string",
            "description": "e.g. \"Oil change\" or \"Annual DOT inspection\"."
          },
          "description": {
            "type": "string"
          },
          "due_date": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "string",
                "format": "date-time"
              }
            ],
            "description": "When it is due, as an ISO timestamp. Required for a recurring task — the series repeats from this date."
          },
          "assignee_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the team member responsible. Use list_users to resolve names."
          },
          "reminders_enabled": {
            "type": "boolean",
            "description": "Whether the assignee is notified as the due date approaches. Defaults to FALSE, so without it the task is a silent to-do."
          },
          "recurrence_type": {
            "type": "string",
            "enum": [
              "single",
              "recurring"
            ],
            "description": "Set to 'recurring' for scheduled maintenance that repeats — an oil change every 3 months, an annual inspection. Default: 'single'."
          },
          "repeat_frequency": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Interval, used when repeat_frequency_unit is 'custom'."
          },
          "repeat_frequency_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How often it repeats. Default: weekly."
          },
          "repeat_frequency_unit_custom": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "Unit the custom interval counts in. Only used with repeat_frequency_unit='custom'."
          },
          "repeat_frequency_schedule": {
            "type": "object",
            "properties": {
              "days": {
                "type": "array",
                "items": {
                  "$ref": "#/properties/repeat_frequency"
                },
                "description": "1-7 for weekdays, 1-31 for days of the month."
              },
              "type": {
                "type": "string",
                "enum": [
                  "weekDays",
                  "monthWeekDays",
                  "monthDays"
                ]
              }
            },
            "required": [
              "days",
              "type"
            ],
            "additionalProperties": false,
            "description": "Which days a custom weekly or monthly pattern lands on. Required for those."
          },
          "repeat_duration": {
            "$ref": "#/properties/repeat_frequency",
            "description": "How long it repeats. Required unless repeat_duration_unit is 'forever'."
          },
          "repeat_duration_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How it ends: 'forever', 'occurrences', or a time unit. Default: forever."
          }
        },
        "required": [
          "equipment_id",
          "title"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_equipment_task",
      "description": "Edit a maintenance task. To mark one done use complete_equipment_task, which for repeating servicing completes only that occurrence.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment the task belongs to."
          },
          "task_id": {
            "$ref": "#/properties/equipment_id",
            "description": "Task ID."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "due_date": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "string",
                "format": "date-time"
              }
            ],
            "description": "ISO timestamp with timezone."
          },
          "assignee_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the team member responsible. Use list_users to resolve names."
          },
          "reminders_enabled": {
            "type": "boolean"
          },
          "update_scope": {
            "type": "string",
            "enum": [
              "single",
              "all",
              "recreate"
            ],
            "description": "For repeating servicing: 'single' changes this one, 'all' applies to future ones, 'recreate' rebuilds the schedule after a pattern change. Default: single."
          },
          "recurrence_type": {
            "type": "string",
            "enum": [
              "single",
              "recurring"
            ],
            "description": "Set to 'recurring' for scheduled maintenance that repeats — an oil change every 3 months, an annual inspection. Default: 'single'."
          },
          "repeat_frequency": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Interval, used when repeat_frequency_unit is 'custom'."
          },
          "repeat_frequency_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How often it repeats. Default: weekly."
          },
          "repeat_frequency_unit_custom": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "Unit the custom interval counts in. Only used with repeat_frequency_unit='custom'."
          },
          "repeat_frequency_schedule": {
            "type": "object",
            "properties": {
              "days": {
                "type": "array",
                "items": {
                  "$ref": "#/properties/repeat_frequency"
                },
                "description": "1-7 for weekdays, 1-31 for days of the month."
              },
              "type": {
                "type": "string",
                "enum": [
                  "weekDays",
                  "monthWeekDays",
                  "monthDays"
                ]
              }
            },
            "required": [
              "days",
              "type"
            ],
            "additionalProperties": false,
            "description": "Which days a custom weekly or monthly pattern lands on. Required for those."
          },
          "repeat_duration": {
            "$ref": "#/properties/repeat_frequency",
            "description": "How long it repeats. Required unless repeat_duration_unit is 'forever'."
          },
          "repeat_duration_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How it ends: 'forever', 'occurrences', or a time unit. Default: forever."
          }
        },
        "required": [
          "equipment_id",
          "task_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "complete_equipment_task",
      "description": "Mark a maintenance task done, or reopen it. For repeating servicing this affects only the single occurrence.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment the task belongs to."
          },
          "task_id": {
            "$ref": "#/properties/equipment_id",
            "description": "Task ID."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "completed",
              "overdue"
            ],
            "description": "completed, open or overdue."
          }
        },
        "required": [
          "equipment_id",
          "task_id",
          "status"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_equipment_task",
      "description": "Delete a maintenance task. To record that it was done, use complete_equipment_task instead — deleting loses the history.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment the task belongs to."
          },
          "task_id": {
            "$ref": "#/properties/equipment_id",
            "description": "Task ID."
          }
        },
        "required": [
          "equipment_id",
          "task_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_equipment_notes",
      "description": "Read the service log for a piece of company equipment: notes, maintenance, repairs and inspections.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment ID"
          },
          "type": {
            "type": "string",
            "enum": [
              "note",
              "maintenance",
              "repair",
              "inspection"
            ],
            "description": "Filter to one kind of entry: note, maintenance, repair, inspection."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "equipment_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_equipment_note",
      "description": "Record work done on a piece of company equipment — a repair, a service, an inspection result, or a plain note. This is the equipment history, so record what happened here rather than only completing the task.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment the entry belongs to."
          },
          "title": {
            "type": "string",
            "description": "e.g. \"Replaced brake pads\"."
          },
          "content": {
            "type": "string",
            "description": "The detail of what was done."
          },
          "type": {
            "type": "string",
            "enum": [
              "note",
              "maintenance",
              "repair",
              "inspection"
            ],
            "description": "note, maintenance, repair or inspection. Default: note."
          },
          "activity_date": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "string",
                "format": "date-time"
              }
            ],
            "description": "When the work actually happened, if not today. Logging a repair a week later should carry the repair date, not the date it was typed up."
          }
        },
        "required": [
          "equipment_id",
          "title"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_equipment_note",
      "description": "Edit an entry in a piece of equipment's service log.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment the entry belongs to."
          },
          "note_id": {
            "$ref": "#/properties/equipment_id",
            "description": "Note ID."
          },
          "title": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "note",
              "maintenance",
              "repair",
              "inspection"
            ]
          },
          "activity_date": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "string",
                "format": "date-time"
              }
            ],
            "description": "When the work happened, as an ISO timestamp with timezone."
          }
        },
        "required": [
          "equipment_id",
          "note_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_equipment_note",
      "description": "Delete an entry from a piece of equipment's service log.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Equipment the entry belongs to."
          },
          "note_id": {
            "$ref": "#/properties/equipment_id",
            "description": "Note ID."
          }
        },
        "required": [
          "equipment_id",
          "note_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_installed_equipment",
      "description": "List equipment installed at customers' properties — furnaces, water heaters, irrigation controllers and so on. This is NOT the company's own trucks and tools; use list_equipment for those. Filter by property or contact to see what is installed for one client.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "property_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Only units at this property."
          },
          "contact_id": {
            "$ref": "#/properties/property_id",
            "description": "Only units belonging to this client, across all their properties."
          },
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "active",
                "needs_service",
                "replaced",
                "removed"
              ]
            },
            "description": "Filter by status: active, needs_service, replaced, removed."
          },
          "search": {
            "type": "string",
            "description": "Search by name, make, model or serial number."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_installed_equipment",
      "description": "Get one installed unit with its property, client and details.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_installed_equipment",
      "description": "Record a unit installed at a customer's property. `property_id` is required — a unit is always installed somewhere. Leave `name` off and it is derived from make and model, then the equipment type. Setting warranty or replacement dates schedules reminders automatically.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "property_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Property the unit is installed at. Required. Use list_properties or list_contact_properties to find it."
          },
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Client who owns it, if different from the property owner."
          },
          "name": {
            "type": "string",
            "description": "Omit to derive from make and model."
          },
          "equipment_type": {
            "type": "string",
            "description": "e.g. \"Furnace\", \"Water heater\"."
          },
          "make": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "serial_number": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "needs_service",
              "replaced",
              "removed"
            ],
            "description": "Default: active."
          },
          "install_date": {
            "type": "string",
            "description": "YYYY-MM-DD."
          },
          "warranty_expiration": {
            "$ref": "#/properties/install_date",
            "description": "YYYY-MM-DD."
          },
          "warranty_number": {
            "type": "string"
          },
          "replacement_date": {
            "$ref": "#/properties/install_date",
            "description": "YYYY-MM-DD."
          },
          "auto_reminders_enabled": {
            "type": "boolean",
            "description": "Whether warranty and replacement reminders are scheduled automatically from the dates above. Defaults to TRUE, so a unit with a warranty date will generate reminders unless this is turned off."
          },
          "installed_by_job_id": {
            "$ref": "#/properties/contact_id",
            "description": "The job that installed it. Also links the unit to that job history."
          }
        },
        "required": [
          "property_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_installed_equipment",
      "description": "Update an installed unit. Send only what changes — the server merges it over the existing record, so a status change alone will not disturb the name or which property it is at. Changing warranty or replacement dates re-syncs the automatic reminders.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          },
          "property_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Move it to a different property."
          },
          "contact_id": {
            "$ref": "#/properties/id"
          },
          "name": {
            "type": "string"
          },
          "equipment_type": {
            "type": "string"
          },
          "make": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "serial_number": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "needs_service",
              "replaced",
              "removed"
            ],
            "description": "active, needs_service, replaced or removed. Use replaced or removed rather than deleting, so the history survives."
          },
          "install_date": {
            "type": "string",
            "description": "YYYY-MM-DD."
          },
          "warranty_expiration": {
            "$ref": "#/properties/install_date",
            "description": "YYYY-MM-DD."
          },
          "warranty_number": {
            "type": "string"
          },
          "replacement_date": {
            "$ref": "#/properties/install_date",
            "description": "YYYY-MM-DD."
          },
          "auto_reminders_enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_installed_equipment",
      "description": "Delete an installed unit and its service history. To record that it was taken out or swapped, set status to 'removed' or 'replaced' instead — that keeps the history for the property.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_installed_equipment_notes",
      "description": "Read the service history for an installed unit: notes, maintenance, repairs and inspections.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "installed_equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          },
          "type": {
            "type": "string",
            "enum": [
              "note",
              "maintenance",
              "repair",
              "inspection"
            ],
            "description": "Filter to one kind of entry."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "installed_equipment_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_installed_equipment_note",
      "description": "Record work done on an installed unit — a service, a repair, an inspection result. This is the unit's history at that property and outlives any one job.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "installed_equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          },
          "title": {
            "type": "string",
            "description": "e.g. \"Replaced igniter\"."
          },
          "content": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "note",
              "maintenance",
              "repair",
              "inspection"
            ],
            "description": "Default: note."
          },
          "activity_date": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "string",
                "format": "date-time"
              }
            ],
            "description": "When the work happened, if not when it was recorded."
          }
        },
        "required": [
          "installed_equipment_id",
          "title"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_installed_equipment_note",
      "description": "Delete an entry from an installed unit's service history.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "installed_equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          },
          "note_id": {
            "$ref": "#/properties/installed_equipment_id",
            "description": "Note ID"
          }
        },
        "required": [
          "installed_equipment_id",
          "note_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_installed_equipment_reminders",
      "description": "List the scheduled reminders on an installed unit. Warranty and replacement reminders are maintained automatically from the unit's dates; custom ones are added by hand.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "installed_equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "installed_equipment_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_installed_equipment_reminder",
      "description": "Schedule a one-off reminder about an installed unit. Do NOT create warranty or replacement reminders this way — those are generated and kept in step automatically from the unit's dates, so a hand-made one duplicates them. Use this for anything else, and note it can go to the customer, the team, or both.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "installed_equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          },
          "name": {
            "type": "string",
            "description": "Internal label for the reminder."
          },
          "subject": {
            "type": "string",
            "description": "Subject line of the message."
          },
          "message": {
            "type": "string",
            "description": "Body of the message."
          },
          "remind_on": {
            "type": "string",
            "description": "Date it fires (YYYY-MM-DD)."
          },
          "reason": {
            "type": "string",
            "enum": [
              "warranty",
              "replacement",
              "custom"
            ],
            "description": "Leave as 'custom'. 'warranty' and 'replacement' are managed automatically."
          },
          "send_customer": {
            "type": "boolean",
            "description": "Send it to the client. Default: false."
          },
          "send_internal": {
            "$ref": "#/properties/send_customer",
            "description": "Send it to the team. Default: true."
          }
        },
        "required": [
          "installed_equipment_id",
          "name",
          "subject",
          "message",
          "remind_on"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_installed_equipment_reminder",
      "description": "Delete a scheduled reminder on an installed unit.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "installed_equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          },
          "notification_id": {
            "$ref": "#/properties/installed_equipment_id",
            "description": "Reminder ID"
          }
        },
        "required": [
          "installed_equipment_id",
          "notification_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_installed_equipment_jobs",
      "description": "List the jobs that have touched an installed unit — its service history by job.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "installed_equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          }
        },
        "required": [
          "installed_equipment_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "link_installed_equipment_to_job",
      "description": "Link an installed unit to a job, recording that the job worked on it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "installed_equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          },
          "job_id": {
            "$ref": "#/properties/installed_equipment_id",
            "description": "Job ID"
          }
        },
        "required": [
          "installed_equipment_id",
          "job_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "unlink_installed_equipment_from_job",
      "description": "Remove the link between a job and an installed unit.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "installed_equipment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Installed equipment ID"
          },
          "job_id": {
            "$ref": "#/properties/installed_equipment_id",
            "description": "Job ID"
          }
        },
        "required": [
          "installed_equipment_id",
          "job_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_requests",
      "description": "List service requests with optional pagination and search",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search requests"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "number",
              "name",
              "status",
              "requested_on",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Filter by contact ID"
          },
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "new",
                "responded",
                "overdue",
                "converted",
                "rejected",
                "archived"
              ]
            },
            "description": "Filter by one or more statuses."
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "$ref": "#/properties/contact_id"
            },
            "description": "Filter to records carrying ANY of these tag IDs (not all). Use list_tags with the matching taggable_type to resolve tag names to IDs first."
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_request",
      "description": "Create a new service request",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Request name/title"
          },
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Associated contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated property ID"
          },
          "assignee_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of assigned team member. Use list_users to resolve names."
          },
          "details": {
            "type": "string",
            "description": "Request details/description"
          },
          "assessment": {
            "type": "string",
            "description": "Assessment notes"
          },
          "requested_on": {
            "type": "string",
            "description": "Date the request was made (YYYY-MM-DD)"
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "responded",
              "overdue",
              "converted",
              "rejected",
              "archived"
            ],
            "description": "Request status (default: new)"
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_request",
      "description": "Get a single service request by ID with expanded details",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Request ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_request",
      "description": "Update an existing service request",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Request ID"
          },
          "name": {
            "type": "string",
            "description": "Request name/title"
          },
          "contact_id": {
            "$ref": "#/properties/id",
            "description": "Associated contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated property ID"
          },
          "assignee_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of assigned team member. Use list_users to resolve names."
          },
          "details": {
            "type": "string",
            "description": "Request details/description"
          },
          "assessment": {
            "type": "string",
            "description": "Assessment notes"
          },
          "requested_on": {
            "type": "string",
            "description": "Date the request was made (YYYY-MM-DD)"
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "responded",
              "overdue",
              "converted",
              "rejected",
              "archived"
            ],
            "description": "Request status"
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "convert_request",
      "description": "Turn a request into a job, quote or invoice. Use this rather than creating the record yourself: it carries over the client and property and marks the request converted in one step. Jobs and quotes retain a source-request link. Invoices do not retain a source-request link; record the returned invoice ID separately if you need to trace the conversion. Creating a job or quote by hand leaves the request sitting in the queue as if nobody had dealt with it. Ask which they want if the user just says \"convert this\" — a quote prices the work first, a job schedules it, an invoice bills for it directly.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Request ID to convert."
          },
          "to": {
            "type": "string",
            "enum": [
              "job",
              "quote",
              "invoice"
            ],
            "description": "What to create: job, quote or invoice."
          },
          "name": {
            "type": "string",
            "description": "Name for the new record. Defaults to the request name plus a suffix."
          }
        },
        "required": [
          "id",
          "to"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_request",
      "description": "Delete a service request by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Request ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_request_status",
      "description": "Update only the status of a service request. Use this instead of update_request when changing status, as status transitions may trigger business logic.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Request ID"
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "responded",
              "overdue",
              "converted",
              "rejected",
              "archived"
            ],
            "description": "New status"
          }
        },
        "required": [
          "id",
          "status"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_new_lead",
      "description": "Create a brand-new lead in one call: contact + optional property + request, atomically linked. Use this for the common \"new inquiry\" happy path where all three records are new. For existing contacts, existing properties, or adding another request/property to an existing contact, use the per-entity tools instead (`create_contact`, `create_contact_property`, `create_request`). Property is optional — omit it if the inquiry has no specific service address; the request will be created without a property link. Returns the created contact_id, property_id (or null), request_id, plus the full created request for follow-up calls.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact": {
            "type": "object",
            "properties": {
              "first_name": {
                "type": "string",
                "description": "First name (required)"
              },
              "last_name": {
                "type": "string",
                "description": "Last name (required)"
              },
              "email": {
                "type": "string",
                "description": "Primary email address"
              },
              "phone": {
                "type": "string",
                "description": "Primary phone number"
              },
              "secondary_email": {
                "type": "string",
                "description": "Secondary email address"
              },
              "secondary_phone": {
                "type": "string",
                "description": "Secondary phone number"
              },
              "company": {
                "type": "string",
                "description": "Company name"
              },
              "company_department": {
                "type": "string",
                "description": "Department within company"
              },
              "company_position": {
                "type": "string",
                "description": "Position/title at company"
              },
              "title": {
                "type": "string",
                "enum": [
                  "mr",
                  "mrs",
                  "miss",
                  "ms",
                  "dr",
                  "prof",
                  "rev"
                ],
                "description": "Honorific title"
              },
              "type": {
                "type": "string",
                "enum": [
                  "none",
                  "customer",
                  "lead",
                  "former_customer",
                  "contractor",
                  "partner",
                  "vendor",
                  "other"
                ],
                "default": "lead",
                "description": "Contact type. Default: 'lead' (the typical value for a new inquiry). Omit unless you specifically need a different value."
              },
              "owner_id": {
                "type": "string",
                "format": "uuid",
                "description": "UUID of the contact owner. Use list_users to resolve names."
              },
              "custom_fields": {
                "type": "object",
                "additionalProperties": {},
                "description": "Custom field values"
              }
            },
            "required": [
              "first_name",
              "last_name"
            ],
            "additionalProperties": false,
            "description": "Contact fields for the new lead."
          },
          "property": {
            "type": "object",
            "properties": {
              "address": {
                "type": "object",
                "properties": {
                  "street": {
                    "type": "string",
                    "description": "Street address line 1"
                  },
                  "street_2": {
                    "type": "string",
                    "description": "Street address line 2"
                  },
                  "city": {
                    "type": "string",
                    "description": "City"
                  },
                  "state": {
                    "type": "string",
                    "description": "State/province"
                  },
                  "postal_code": {
                    "type": "string",
                    "description": "Postal/zip code"
                  },
                  "country": {
                    "type": "string",
                    "description": "Country"
                  }
                },
                "additionalProperties": false,
                "description": "Property address"
              },
              "property_type": {
                "type": "string",
                "enum": [
                  "single-family",
                  "apartment",
                  "complex",
                  "townhouse",
                  "land",
                  "commercial",
                  "other"
                ],
                "default": "single-family",
                "description": "Property type. Default: 'single-family'. Omit unless you specifically need a different value."
              },
              "role": {
                "type": "string",
                "enum": [
                  "owner",
                  "tenant",
                  "manager",
                  "agent",
                  "other"
                ],
                "default": "owner",
                "description": "Contact's role for this property. Default: 'owner'. Omit unless you specifically need a different value."
              }
            },
            "required": [
              "address"
            ],
            "additionalProperties": false,
            "description": "Optional property (service address) to create and link to the contact. Omit when the lead has no specific address yet."
          },
          "request": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "description": "Request name/title"
              },
              "assignee_id": {
                "type": "string",
                "format": "uuid",
                "description": "UUID of assigned team member. Use `list_users` to resolve a user name to a UUID."
              },
              "details": {
                "type": "string",
                "description": "Request details/description"
              },
              "assessment": {
                "type": "string",
                "description": "Assessment notes"
              },
              "requested_on": {
                "type": "string",
                "description": "Date the request was made (YYYY-MM-DD)"
              },
              "status": {
                "type": "string",
                "enum": [
                  "new",
                  "responded",
                  "overdue",
                  "converted",
                  "rejected",
                  "archived"
                ],
                "default": "new",
                "description": "Request status. Default: 'new'. Omit unless you specifically need a different value."
              },
              "custom_fields": {
                "type": "object",
                "additionalProperties": {},
                "description": "Custom field values"
              }
            },
            "additionalProperties": false,
            "description": "Service request fields. contact_id and property_id are set automatically."
          }
        },
        "required": [
          "contact",
          "request"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_quotes",
      "description": "List quotes with optional pagination and search",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search quotes"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "number",
              "name",
              "status",
              "total",
              "date",
              "expire_on",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Filter by contact ID"
          },
          "exclude_statuses": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "draft",
                "awaiting_response",
                "accepted",
                "declined",
                "expired",
                "archived",
                "awaiting_deposit"
              ]
            },
            "description": "Exclude quotes with any of these statuses."
          },
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "draft",
                "awaiting_response",
                "accepted",
                "declined",
                "expired",
                "archived",
                "awaiting_deposit"
              ]
            },
            "description": "Filter by one or more statuses."
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "$ref": "#/properties/contact_id"
            },
            "description": "Filter to records carrying ANY of these tag IDs (not all). Use list_tags with the matching taggable_type to resolve tag names to IDs first."
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_quote",
      "description": "Create a new quote",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Quote name/title"
          },
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Associated contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated property ID"
          },
          "request_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated request ID"
          },
          "salesperson_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of salesperson. Use list_users to resolve names."
          },
          "template_id": {
            "$ref": "#/properties/contact_id",
            "description": "Quote template ID"
          },
          "date": {
            "type": "string",
            "description": "Quote date (YYYY-MM-DD)"
          },
          "expire_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "string",
                "format": "date-time"
              }
            ],
            "description": "Expiration date (YYYY-MM-DD)"
          },
          "message": {
            "type": "string",
            "description": "Message to client"
          },
          "line_items": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "lineItem"
                    },
                    "name": {
                      "type": "string",
                      "description": "Item name"
                    },
                    "description": {
                      "type": "string",
                      "default": "",
                      "description": "Plain text description for this line item. Omit when not needed."
                    },
                    "quantity": {
                      "type": "number",
                      "default": 1,
                      "description": "Quantity"
                    },
                    "unit_price": {
                      "type": "number",
                      "description": "Price per unit"
                    },
                    "taxable": {
                      "type": "boolean",
                      "description": "Whether the item is taxable"
                    },
                    "optional": {
                      "type": "boolean",
                      "description": "Whether the item is optional"
                    }
                  },
                  "required": [
                    "_type",
                    "name",
                    "unit_price"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "image"
                    },
                    "image_path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Storage path returned by a prior `upload_file` call. Upload with module_type=\"workspace\", category=\"line_item\", is_public=true to get a usable path."
                    },
                    "image_id": {
                      "type": "integer",
                      "description": "Upload link ID (`id`) returned by the same `upload_file` call."
                    },
                    "description": {
                      "type": "string",
                      "description": "Caption shown beneath the image in the line items list."
                    }
                  },
                  "required": [
                    "_type",
                    "image_path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Array of line item objects. Two shapes are accepted: a regular priced row (`{ name, quantity, unit_price }`) or an inline image row (`{ _type: \"image\", image_path, image_id, description }`). For image rows: first call `upload_file` with `module_type=\"workspace\"`, `category=\"line_item\"`, `is_public=true` to upload the image, then pass the returned `path` as `image_path` and `id` as `image_id`."
          },
          "discount": {
            "type": "number",
            "description": "Discount amount (default: 0)"
          },
          "discount_unit": {
            "type": "string",
            "enum": [
              "percent",
              "amount"
            ],
            "description": "How the discount is expressed. One of: 'percent' (a percentage of the subtotal) or 'amount' (a fixed currency amount). Default: 'percent'."
          },
          "deposit": {
            "type": "number",
            "description": "Deposit amount (default: 0)"
          },
          "deposit_unit": {
            "$ref": "#/properties/discount_unit",
            "description": "How the deposit is expressed. One of: 'percent' or 'amount'. Default: 'percent'."
          },
          "tax_rate": {
            "type": "number",
            "description": "Tax rate percentage (default: 0)"
          },
          "tax_rate_id": {
            "$ref": "#/properties/contact_id",
            "description": "Tax rate preset ID"
          },
          "total": {
            "type": "number",
            "description": "Quote total"
          },
          "reminders_enabled": {
            "type": "boolean",
            "description": "Whether BlueSuite automatically emails the client reminders about this quote. Default: true."
          },
          "waive_credit_card_fee": {
            "$ref": "#/properties/reminders_enabled",
            "description": "Skip the workspace's online processing fee for this record. Only meaningful when the workspace passes processing fees on to clients. Carries over to jobs and invoices created from this quote. Default: false."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "awaiting_response",
              "accepted",
              "declined",
              "expired",
              "archived",
              "awaiting_deposit"
            ],
            "description": "Quote status (default: draft)"
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_quote",
      "description": "Get a single quote by ID with expanded details",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Quote ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_quote",
      "description": "Update an existing quote",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Quote ID"
          },
          "name": {
            "type": "string",
            "description": "Quote name/title"
          },
          "contact_id": {
            "$ref": "#/properties/id",
            "description": "Associated contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated property ID"
          },
          "request_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated request ID"
          },
          "salesperson_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of salesperson. Use list_users to resolve names."
          },
          "template_id": {
            "$ref": "#/properties/contact_id",
            "description": "Quote template ID"
          },
          "date": {
            "type": "string",
            "description": "Quote date (YYYY-MM-DD)"
          },
          "expire_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "string",
                "format": "date-time"
              }
            ],
            "description": "Expiration date (YYYY-MM-DD)"
          },
          "message": {
            "type": "string",
            "description": "Message to client"
          },
          "line_items": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "lineItem"
                    },
                    "name": {
                      "type": "string",
                      "description": "Item name"
                    },
                    "description": {
                      "type": "string",
                      "default": "",
                      "description": "Plain text description for this line item. Omit when not needed."
                    },
                    "quantity": {
                      "type": "number",
                      "default": 1,
                      "description": "Quantity"
                    },
                    "unit_price": {
                      "type": "number",
                      "description": "Price per unit"
                    },
                    "taxable": {
                      "type": "boolean",
                      "description": "Whether the item is taxable"
                    },
                    "optional": {
                      "type": "boolean",
                      "description": "Whether the item is optional"
                    }
                  },
                  "required": [
                    "_type",
                    "name",
                    "unit_price"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "image"
                    },
                    "image_path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Storage path returned by a prior `upload_file` call. Upload with module_type=\"workspace\", category=\"line_item\", is_public=true to get a usable path."
                    },
                    "image_id": {
                      "type": "integer",
                      "description": "Upload link ID (`id`) returned by the same `upload_file` call."
                    },
                    "description": {
                      "type": "string",
                      "description": "Caption shown beneath the image in the line items list."
                    }
                  },
                  "required": [
                    "_type",
                    "image_path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Array of line item objects. Two shapes are accepted: a regular priced row (`{ name, quantity, unit_price }`) or an inline image row (`{ _type: \"image\", image_path, image_id, description }`). For image rows: first call `upload_file` with `module_type=\"workspace\"`, `category=\"line_item\"`, `is_public=true` to upload the image, then pass the returned `path` as `image_path` and `id` as `image_id`."
          },
          "discount": {
            "type": "number",
            "description": "Discount amount"
          },
          "discount_unit": {
            "type": "string",
            "enum": [
              "percent",
              "amount"
            ],
            "description": "How the discount is expressed. One of: 'percent' (a percentage of the subtotal) or 'amount' (a fixed currency amount)."
          },
          "deposit": {
            "type": "number",
            "description": "Deposit amount"
          },
          "deposit_unit": {
            "$ref": "#/properties/discount_unit",
            "description": "How the deposit is expressed. One of: 'percent' or 'amount'."
          },
          "tax_rate": {
            "type": "number",
            "description": "Tax rate percentage"
          },
          "tax_rate_id": {
            "$ref": "#/properties/contact_id",
            "description": "Tax rate preset ID"
          },
          "total": {
            "type": "number",
            "description": "Quote total"
          },
          "reminders_enabled": {
            "type": "boolean",
            "description": "Whether BlueSuite automatically emails the client reminders about this quote. Default: true."
          },
          "waive_credit_card_fee": {
            "$ref": "#/properties/reminders_enabled",
            "description": "Skip the workspace's online processing fee for this record. Only meaningful when the workspace passes processing fees on to clients. Carries over to jobs and invoices created from this quote. Default: false."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "awaiting_response",
              "accepted",
              "declined",
              "expired",
              "archived",
              "awaiting_deposit"
            ],
            "description": "Quote status"
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_quote",
      "description": "Delete a quote by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Quote ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_quote_status",
      "description": "Record a change to a quote's status. This does NOT email anyone. To actually deliver a quote to the client, use send_notification with type=\"quote_to_customer\", which delivers it and moves the quote to awaiting response. Use this tool for bookkeeping: marking a quote accepted, declined or archived after hearing back some other way.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Quote ID"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "awaiting_response",
              "accepted",
              "declined",
              "expired",
              "archived",
              "awaiting_deposit"
            ],
            "description": "New status"
          },
          "comment": {
            "type": "string",
            "description": "Optional comment for the status change"
          }
        },
        "required": [
          "id",
          "status"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_quote_templates",
      "description": "List quote templates. Templates are reusable starting points for creating new quotes with pre-filled line items, pricing, and messages.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search by template name"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "template_name",
              "total",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_quote_template",
      "description": "Create a new quote template. Templates store line items, pricing, discounts, deposits, tax rates, and messages that can be reused when creating new quotes.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "template_name": {
            "type": "string",
            "description": "Template name (internal label)"
          },
          "name": {
            "type": "string",
            "description": "Default quote name/title when using this template"
          },
          "description": {
            "type": "string",
            "description": "Template description"
          },
          "message": {
            "type": "string",
            "description": "Default message to client"
          },
          "line_items": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "lineItem"
                    },
                    "name": {
                      "type": "string",
                      "description": "Item name"
                    },
                    "description": {
                      "type": "string",
                      "default": "",
                      "description": "Plain text description for this line item. Omit when not needed."
                    },
                    "quantity": {
                      "type": "number",
                      "default": 1,
                      "description": "Quantity"
                    },
                    "unit_price": {
                      "type": "number",
                      "description": "Price per unit"
                    },
                    "taxable": {
                      "type": "boolean",
                      "description": "Whether the item is taxable"
                    },
                    "optional": {
                      "type": "boolean",
                      "description": "Whether the item is optional"
                    }
                  },
                  "required": [
                    "_type",
                    "name",
                    "unit_price"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "image"
                    },
                    "image_path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Storage path returned by a prior `upload_file` call. Upload with module_type=\"workspace\", category=\"line_item\", is_public=true to get a usable path."
                    },
                    "image_id": {
                      "type": "integer",
                      "description": "Upload link ID (`id`) returned by the same `upload_file` call."
                    },
                    "description": {
                      "type": "string",
                      "description": "Caption shown beneath the image in the line items list."
                    }
                  },
                  "required": [
                    "_type",
                    "image_path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Array of line item objects. Two shapes are accepted: a regular priced row (`{ name, quantity, unit_price }`) or an inline image row (`{ _type: \"image\", image_path, image_id, description }`). For image rows: first call `upload_file` with `module_type=\"workspace\"`, `category=\"line_item\"`, `is_public=true` to upload the image, then pass the returned `path` as `image_path` and `id` as `image_id`."
          },
          "discount": {
            "type": "number",
            "description": "Discount amount (default: 0)"
          },
          "discount_unit": {
            "type": "string",
            "enum": [
              "percent",
              "amount"
            ],
            "description": "How the discount is expressed. One of: 'percent' (a percentage of the subtotal) or 'amount' (a fixed currency amount). Default: 'percent'."
          },
          "deposit": {
            "type": "number",
            "description": "Deposit amount (default: 0)"
          },
          "deposit_unit": {
            "$ref": "#/properties/discount_unit",
            "description": "How the deposit is expressed. One of: 'percent' or 'amount'. Default: 'percent'."
          },
          "tax_rate": {
            "type": "number",
            "description": "Tax rate percentage (default: 0)"
          },
          "tax_rate_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Tax rate preset ID"
          },
          "total": {
            "type": "number",
            "description": "Template total"
          }
        },
        "required": [
          "template_name"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_quote_template",
      "description": "Get a single quote template by ID with expanded details (tax rate, line items, creator)",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Quote template ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_quote_template",
      "description": "Update an existing quote template. Modifying a quote template will not affect existing quotes that use it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Quote template ID"
          },
          "template_name": {
            "type": "string",
            "description": "Template name (internal label)"
          },
          "name": {
            "type": "string",
            "description": "Default quote name/title"
          },
          "description": {
            "type": "string",
            "description": "Template description"
          },
          "message": {
            "type": "string",
            "description": "Default message to client"
          },
          "line_items": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "lineItem"
                    },
                    "name": {
                      "type": "string",
                      "description": "Item name"
                    },
                    "description": {
                      "type": "string",
                      "default": "",
                      "description": "Plain text description for this line item. Omit when not needed."
                    },
                    "quantity": {
                      "type": "number",
                      "default": 1,
                      "description": "Quantity"
                    },
                    "unit_price": {
                      "type": "number",
                      "description": "Price per unit"
                    },
                    "taxable": {
                      "type": "boolean",
                      "description": "Whether the item is taxable"
                    },
                    "optional": {
                      "type": "boolean",
                      "description": "Whether the item is optional"
                    }
                  },
                  "required": [
                    "_type",
                    "name",
                    "unit_price"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "image"
                    },
                    "image_path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Storage path returned by a prior `upload_file` call. Upload with module_type=\"workspace\", category=\"line_item\", is_public=true to get a usable path."
                    },
                    "image_id": {
                      "type": "integer",
                      "description": "Upload link ID (`id`) returned by the same `upload_file` call."
                    },
                    "description": {
                      "type": "string",
                      "description": "Caption shown beneath the image in the line items list."
                    }
                  },
                  "required": [
                    "_type",
                    "image_path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Array of line item objects. Two shapes are accepted: a regular priced row (`{ name, quantity, unit_price }`) or an inline image row (`{ _type: \"image\", image_path, image_id, description }`). For image rows: first call `upload_file` with `module_type=\"workspace\"`, `category=\"line_item\"`, `is_public=true` to upload the image, then pass the returned `path` as `image_path` and `id` as `image_id`."
          },
          "discount": {
            "type": "number",
            "description": "Discount amount"
          },
          "discount_unit": {
            "type": "string",
            "enum": [
              "percent",
              "amount"
            ],
            "description": "How the discount is expressed. One of: 'percent' (a percentage of the subtotal) or 'amount' (a fixed currency amount)."
          },
          "deposit": {
            "type": "number",
            "description": "Deposit amount"
          },
          "deposit_unit": {
            "$ref": "#/properties/discount_unit",
            "description": "How the deposit is expressed. One of: 'percent' or 'amount'."
          },
          "tax_rate": {
            "type": "number",
            "description": "Tax rate percentage"
          },
          "tax_rate_id": {
            "$ref": "#/properties/id",
            "description": "Tax rate preset ID"
          },
          "total": {
            "type": "number",
            "description": "Template total"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_quote_from_template",
      "description": "Create a new draft quote from an existing quote template. The new quote inherits the template's line items, pricing, discounts, deposits, tax rate, message, and payment instructions. Requires the quotes:write scope.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "template_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Quote template ID to create the quote from"
          },
          "contact_id": {
            "$ref": "#/properties/template_id",
            "description": "Client to attach the new quote to. A template carries pricing but no client, so without this the quote arrives unaddressed."
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Property the work is for."
          },
          "name": {
            "type": "string",
            "description": "Override the quote name copied from the template."
          },
          "salesperson_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the salesperson. Use list_users to resolve names."
          },
          "expire_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "string",
                "format": "date-time"
              }
            ],
            "description": "Expiry date (YYYY-MM-DD)."
          }
        },
        "required": [
          "template_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_quote_template",
      "description": "Delete a quote template by ID. Deleting a quote template will not affect existing quotes that use it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Quote template ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_jobs",
      "description": "List jobs with optional pagination and search",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search jobs"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "number",
              "name",
              "status",
              "type",
              "total",
              "expected_end_date",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Filter by contact ID"
          },
          "quote_id": {
            "$ref": "#/properties/contact_id",
            "description": "Filter by quote ID"
          },
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "draft",
                "scheduled",
                "in_progress",
                "on_hold",
                "completed",
                "cancelled"
              ]
            },
            "description": "Filter by one or more statuses."
          },
          "derived_state": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "missed",
                "overdue",
                "action_required",
                "needs_invoicing",
                "unscheduled",
                "awaiting_payment"
              ]
            },
            "description": "Filter by one or more derived conditions: needs_invoicing (work done, not yet invoiced), unscheduled (no appointment booked), missed, overdue, awaiting_payment, action_required. Use this for questions about what needs attention rather than filtering on status."
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "$ref": "#/properties/contact_id"
            },
            "description": "Filter to records carrying ANY of these tag IDs (not all). Use list_tags with the matching taggable_type to resolve tag names to IDs first."
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_job",
      "description": "Create a new job",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Job name/title"
          },
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Associated contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated property ID"
          },
          "request_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated request ID"
          },
          "quote_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated quote ID"
          },
          "salesperson_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of salesperson. Use list_users to resolve names."
          },
          "line_items": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "lineItem"
                    },
                    "name": {
                      "type": "string",
                      "description": "Item name"
                    },
                    "description": {
                      "type": "string",
                      "default": "",
                      "description": "Plain text description for this line item. Omit when not needed."
                    },
                    "quantity": {
                      "type": "number",
                      "default": 1,
                      "description": "Quantity"
                    },
                    "unit_price": {
                      "type": "number",
                      "description": "Price per unit"
                    },
                    "taxable": {
                      "type": "boolean",
                      "description": "Whether the item is taxable"
                    },
                    "optional": {
                      "type": "boolean",
                      "description": "Whether the item is optional"
                    }
                  },
                  "required": [
                    "_type",
                    "name",
                    "unit_price"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "image"
                    },
                    "image_path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Storage path returned by a prior `upload_file` call. Upload with module_type=\"workspace\", category=\"line_item\", is_public=true to get a usable path."
                    },
                    "image_id": {
                      "type": "integer",
                      "description": "Upload link ID (`id`) returned by the same `upload_file` call."
                    },
                    "description": {
                      "type": "string",
                      "description": "Caption shown beneath the image in the line items list."
                    }
                  },
                  "required": [
                    "_type",
                    "image_path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Array of line item objects. Two shapes are accepted: a regular priced row (`{ name, quantity, unit_price }`) or an inline image row (`{ _type: \"image\", image_path, image_id, description }`). For image rows: first call `upload_file` with `module_type=\"workspace\"`, `category=\"line_item\"`, `is_public=true` to upload the image, then pass the returned `path` as `image_path` and `id` as `image_id`."
          },
          "discount": {
            "type": "number",
            "description": "Discount amount (default: 0)"
          },
          "discount_unit": {
            "type": "string",
            "enum": [
              "percent",
              "amount"
            ],
            "description": "How the discount is expressed. One of: 'percent' (a percentage of the subtotal) or 'amount' (a fixed currency amount). Default: 'percent'."
          },
          "deposit": {
            "type": "number",
            "description": "Deposit amount (default: 0)"
          },
          "deposit_unit": {
            "$ref": "#/properties/discount_unit",
            "description": "How the deposit is expressed. One of: 'percent' or 'amount'. Default: 'percent'."
          },
          "tax_rate": {
            "type": "number",
            "description": "Tax rate percentage (default: 0)"
          },
          "tax_rate_id": {
            "$ref": "#/properties/contact_id",
            "description": "Tax rate preset ID"
          },
          "total": {
            "type": "number",
            "description": "Job total"
          },
          "type": {
            "type": "string",
            "enum": [
              "one-off",
              "recurring"
            ],
            "description": "Job type (default: one-off)"
          },
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "cancelled"
            ],
            "description": "Initial status. Only completed and cancelled can be set; otherwise status follows the job's appointments."
          },
          "billing_type": {
            "type": "string",
            "enum": [
              "per_visit",
              "manual"
            ],
            "description": "How the job gets invoiced. 'per_visit' automatically creates and sends an invoice each time an appointment is completed. 'manual' means the business invoices on its own schedule. Defaults to 'per_visit' — ask the user which they want for recurring work rather than assuming, because the default sends real invoices to their client."
          },
          "invoice_autopay": {
            "type": "boolean",
            "description": "Charge the client's saved payment method automatically when an invoice is auto-created. Only meaningful with billing_type='per_visit'. Default: false."
          },
          "invoice_payment_terms": {
            "type": "string",
            "enum": [
              "due_on_receipt",
              "net_7",
              "net_14",
              "net_30",
              "net_60",
              "net_90"
            ],
            "description": "Payment terms applied to invoices generated from this job."
          },
          "waive_credit_card_fee": {
            "type": "boolean",
            "description": "Skip the workspace's online processing fee for this record. Only meaningful when the workspace passes processing fees on to clients. Nothing is charged against a job directly; the waiver rides onto invoices created from it. Default: false."
          },
          "expected_end_date": {
            "type": "string",
            "description": "Expected end date (YYYY-MM-DD)"
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_job",
      "description": "Get a single job by ID with expanded details",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_job",
      "description": "Update an existing job. For an in-progress job that requires change orders, line items, discounts, and taxes cannot be changed here; create a change order in the dashboard. Omit line_items when only updating job details. Setting `status` here applies the same completion rules as `update_job_status` (for example, required forms must be filled in before a job can be completed), so prefer that tool when status is the only change.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          },
          "name": {
            "type": "string",
            "description": "Job name/title"
          },
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "cancelled",
              "reopen"
            ],
            "description": "Change the job status as part of this update. Prefer `update_job_status` when status is the only thing changing. Draft, Scheduled and Ongoing are derived from appointments and cannot be set."
          },
          "contact_id": {
            "$ref": "#/properties/id",
            "description": "Associated contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated property ID"
          },
          "request_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated request ID"
          },
          "quote_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated quote ID"
          },
          "salesperson_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of salesperson. Use list_users to resolve names."
          },
          "line_items": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "lineItem"
                    },
                    "name": {
                      "type": "string",
                      "description": "Item name"
                    },
                    "description": {
                      "type": "string",
                      "default": "",
                      "description": "Plain text description for this line item. Omit when not needed."
                    },
                    "quantity": {
                      "type": "number",
                      "default": 1,
                      "description": "Quantity"
                    },
                    "unit_price": {
                      "type": "number",
                      "description": "Price per unit"
                    },
                    "taxable": {
                      "type": "boolean",
                      "description": "Whether the item is taxable"
                    },
                    "optional": {
                      "type": "boolean",
                      "description": "Whether the item is optional"
                    }
                  },
                  "required": [
                    "_type",
                    "name",
                    "unit_price"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "image"
                    },
                    "image_path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Storage path returned by a prior `upload_file` call. Upload with module_type=\"workspace\", category=\"line_item\", is_public=true to get a usable path."
                    },
                    "image_id": {
                      "type": "integer",
                      "description": "Upload link ID (`id`) returned by the same `upload_file` call."
                    },
                    "description": {
                      "type": "string",
                      "description": "Caption shown beneath the image in the line items list."
                    }
                  },
                  "required": [
                    "_type",
                    "image_path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Array of line item objects. Two shapes are accepted: a regular priced row (`{ name, quantity, unit_price }`) or an inline image row (`{ _type: \"image\", image_path, image_id, description }`). For image rows: first call `upload_file` with `module_type=\"workspace\"`, `category=\"line_item\"`, `is_public=true` to upload the image, then pass the returned `path` as `image_path` and `id` as `image_id`."
          },
          "discount": {
            "type": "number",
            "description": "Discount amount"
          },
          "discount_unit": {
            "type": "string",
            "enum": [
              "percent",
              "amount"
            ],
            "description": "How the discount is expressed. One of: 'percent' (a percentage of the subtotal) or 'amount' (a fixed currency amount)."
          },
          "deposit": {
            "type": "number",
            "description": "Deposit amount"
          },
          "deposit_unit": {
            "$ref": "#/properties/discount_unit",
            "description": "How the deposit is expressed. One of: 'percent' or 'amount'."
          },
          "tax_rate": {
            "type": "number",
            "description": "Tax rate percentage"
          },
          "tax_rate_id": {
            "$ref": "#/properties/contact_id",
            "description": "Tax rate preset ID"
          },
          "total": {
            "type": "number",
            "description": "Job total"
          },
          "type": {
            "type": "string",
            "enum": [
              "one-off",
              "recurring"
            ],
            "description": "Job type"
          },
          "billing_type": {
            "type": "string",
            "enum": [
              "per_visit",
              "manual"
            ],
            "description": "How the job gets invoiced. 'per_visit' automatically creates and sends an invoice each time an appointment is completed. 'manual' means the business invoices on its own schedule. Defaults to 'per_visit' — ask the user which they want for recurring work rather than assuming, because the default sends real invoices to their client."
          },
          "invoice_autopay": {
            "type": "boolean",
            "description": "Charge the client's saved payment method automatically when an invoice is auto-created. Only meaningful with billing_type='per_visit'."
          },
          "invoice_payment_terms": {
            "type": "string",
            "enum": [
              "due_on_receipt",
              "net_7",
              "net_14",
              "net_30",
              "net_60",
              "net_90"
            ],
            "description": "Payment terms applied to invoices generated from this job."
          },
          "waive_credit_card_fee": {
            "type": "boolean",
            "description": "Skip the workspace's online processing fee for this record. Only meaningful when the workspace passes processing fees on to clients. Nothing is charged against a job directly; the waiver rides onto invoices created from it. Default: false."
          },
          "expected_end_date": {
            "type": "string",
            "description": "Expected end date (YYYY-MM-DD)"
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "setup_recurring_job",
      "description": "Put a job on a recurring appointment schedule — weekly lawn care, quarterly maintenance, and so on. Use this rather than create_event for anything tied to a job: it marks the job recurring, saves the billing settings the completion flow reads, and creates the appointment series in one step. A recurring job created without this stays unscheduled and never generates visits. Confirm the billing_type with the user first, since per_visit sends real invoices to their client after every visit.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID to schedule."
          },
          "start_date": {
            "type": "string",
            "description": "Date of the first appointment (YYYY-MM-DD)."
          },
          "end_date": {
            "$ref": "#/properties/start_date",
            "description": "End date of each appointment, for visits spanning more than one day."
          },
          "start_time": {
            "type": "string",
            "description": "Start time (HH:MM). Required unless all_day is true."
          },
          "end_time": {
            "$ref": "#/properties/start_time",
            "description": "End time (HH:MM). Required unless all_day is true."
          },
          "all_day": {
            "type": "boolean",
            "description": "Whether each visit takes the whole day."
          },
          "multi_day": {
            "$ref": "#/properties/all_day",
            "description": "Whether each visit spans multiple days."
          },
          "is_flexible": {
            "$ref": "#/properties/all_day",
            "description": "Whether scheduling may move the visit within the day."
          },
          "duration_minutes": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Expected length of each visit in minutes."
          },
          "assignee_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "UUIDs of the team members assigned. Use list_users to resolve names."
          },
          "billing_type": {
            "type": "string",
            "enum": [
              "per_visit",
              "manual"
            ],
            "description": "How the job gets invoiced. 'per_visit' automatically creates and sends an invoice each time an appointment is completed. 'manual' means the business invoices on its own schedule. Defaults to 'per_visit' — ask the user which they want for recurring work rather than assuming, because the default sends real invoices to their client."
          },
          "payment_terms": {
            "type": "string",
            "enum": [
              "due_on_receipt",
              "net_7",
              "net_14",
              "net_30",
              "net_60",
              "net_90"
            ],
            "description": "Payment terms on invoices generated from these visits."
          },
          "repeat_frequency": {
            "$ref": "#/properties/duration_minutes",
            "description": "Interval between visits, used when repeat_frequency_unit is 'custom' (2 with a custom weekly unit means every 2 weeks). Default: 1."
          },
          "repeat_frequency_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How often the visit repeats: daily, weekly, monthly, yearly, or 'custom'. Default: weekly."
          },
          "repeat_frequency_unit_custom": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "Unit the custom interval counts in. Only used when repeat_frequency_unit is 'custom'."
          },
          "repeat_frequency_schedule": {
            "type": "object",
            "properties": {
              "days": {
                "type": "array",
                "items": {
                  "$ref": "#/properties/duration_minutes"
                },
                "description": "Days to repeat on: 1-7 for weekdays, 1-31 for days of the month."
              },
              "type": {
                "type": "string",
                "enum": [
                  "weekDays",
                  "monthWeekDays",
                  "monthDays"
                ]
              }
            },
            "required": [
              "days",
              "type"
            ],
            "additionalProperties": false,
            "description": "Which days a custom weekly or monthly pattern lands on. Required for those patterns."
          },
          "repeat_duration": {
            "$ref": "#/properties/duration_minutes",
            "description": "How long the schedule runs. With repeat_duration_unit='occurrences' this is a visit count. Required unless it repeats forever."
          },
          "repeat_duration_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How the schedule ends: 'forever', 'occurrences' (a fixed number of visits), or a time unit. Default: forever."
          }
        },
        "required": [
          "id",
          "start_date"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "end_recurring_job_schedule",
      "description": "Stop a job's recurring schedule from a given date. Use this when the user says to stop, cancel or end repeating work — do NOT delete the job, which would take its history with it. This is a cutoff, not a delete: visits after the date are removed, while visits on or before it, and anything already completed or invoiced, are kept. Confirm the date with the user, since \"stop after this month\" and \"stop immediately\" remove different visits.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID whose schedule should end."
          },
          "end_date": {
            "type": "string",
            "description": "Last date the schedule runs (YYYY-MM-DD). Visits after this date are removed."
          }
        },
        "required": [
          "id",
          "end_date"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_job",
      "description": "Delete a job and everything that hangs off it. Every appointment cascades away, including completed visits, along with expenses and change orders; invoices and time entries survive but lose their link to the job. For a recurring job this destroys the whole visit history — to stop repeating work use end_recurring_job_schedule, which keeps the past and only removes visits after a cutoff. Confirm with the user first; there is no undo.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "hold_job",
      "description": "Place a job on hold with a reason, optional notes, and an optional follow-up date. Confirm whether upcoming unstarted appointments should be cancelled to release their time slots or kept booked. Completed and in-progress visits are preserved. Existing invoices and payments are unaffected. The person placing the hold receives email and dashboard follow-ups when due. For recurring jobs, cancel_appointments=true also pauses new visits; false keeps existing appointments and continues normal generation. Service plans are not supported.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          },
          "reason": {
            "type": "string",
            "enum": [
              "customer",
              "materials",
              "approval",
              "weather",
              "other"
            ]
          },
          "notes": {
            "type": "string",
            "maxLength": 2000
          },
          "follow_up_on": {
            "type": "string",
            "description": "Optional follow-up date, YYYY-MM-DD. Does not automatically resume the job."
          },
          "cancel_appointments": {
            "type": "boolean",
            "description": "Required explicit choice: true cancels upcoming unstarted appointments; false keeps them booked."
          }
        },
        "required": [
          "id",
          "reason",
          "cancel_appointments"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "resume_job",
      "description": "Resume an on-hold job. For recurring jobs whose hold_cancel_appointments is true and whose schedule has not been explicitly ended, resume_on is required: visits restart on the original recurrence pattern from that date without catch-up visits. If all schedules have been explicitly ended, omit resume_on; resuming clears the hold without restarting them. If hold_cancel_appointments is false, omit resume_on; appointments continue unchanged. End dates and occurrence limits stay unchanged. Read the current job first and pass its held_at timestamp so a stale request cannot resume a newer hold. Status is recalculated from existing work. Cancelled records stay in history. Recurring visits are generated again from resume_on; one-off appointments must be scheduled separately.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          },
          "expected_held_at": {
            "type": "string",
            "format": "date-time",
            "description": "Exact held_at timestamp from get_job."
          },
          "resume_on": {
            "type": "string",
            "description": "Required only when hold_cancel_appointments is true on a recurring job with a schedule that has not been explicitly ended: resume appointments on or after this date (YYYY-MM-DD), today or later."
          }
        },
        "required": [
          "id",
          "expected_held_at"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_job_status",
      "description": "Change a job's status with completion rules enforced. Use hold_job and resume_job to manage holds. Draft, Scheduled and Ongoing are derived from the job's appointments and cannot be set by hand. Use \"reopen\" to bring a completed or cancelled job back; the correct status is then re-derived from its appointments.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          },
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "cancelled",
              "reopen"
            ],
            "description": "completed, cancelled, or reopen. Completing fails if the job has required forms that are not filled in yet."
          }
        },
        "required": [
          "id",
          "status"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_invoices",
      "description": "List invoices with optional pagination, search, and filters",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search invoices"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "number",
              "name",
              "status",
              "type",
              "total",
              "date",
              "due_date",
              "send_on",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Filter by contact ID"
          },
          "job_id": {
            "$ref": "#/properties/contact_id",
            "description": "Filter by job ID"
          },
          "exclude_children": {
            "type": "boolean",
            "description": "Exclude child invoices (recurring children)"
          },
          "exclude_statuses": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "draft",
                "sent",
                "paid",
                "overdue",
                "cancelled",
                "partially_paid",
                "scheduled"
              ]
            },
            "description": "Exclude invoices with any of these statuses."
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "$ref": "#/properties/contact_id"
            },
            "description": "Filter to records carrying ANY of these tag IDs (not all). Use list_tags with the matching taggable_type to resolve tag names to IDs first."
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_invoice",
      "description": "Create a new invoice",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Invoice name/title"
          },
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Associated contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated property ID"
          },
          "job_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated job ID"
          },
          "quote_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated quote ID"
          },
          "salesperson_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of salesperson. Use list_users to resolve names."
          },
          "date": {
            "type": "string",
            "description": "Invoice date (YYYY-MM-DD)"
          },
          "due_date": {
            "$ref": "#/properties/date",
            "description": "Due date (YYYY-MM-DD)"
          },
          "send_on": {
            "$ref": "#/properties/date",
            "description": "Scheduled send date (YYYY-MM-DD)"
          },
          "message": {
            "type": "string",
            "description": "Message to client"
          },
          "payment_terms": {
            "type": "string",
            "enum": [
              "due_on_receipt",
              "net_7",
              "net_14",
              "net_30",
              "net_60",
              "net_90"
            ],
            "description": "Payment terms (default: due_on_receipt)"
          },
          "line_items": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "lineItem"
                    },
                    "name": {
                      "type": "string",
                      "description": "Item name"
                    },
                    "description": {
                      "type": "string",
                      "default": "",
                      "description": "Plain text description for this line item. Omit when not needed."
                    },
                    "quantity": {
                      "type": "number",
                      "default": 1,
                      "description": "Quantity"
                    },
                    "unit_price": {
                      "type": "number",
                      "description": "Price per unit"
                    },
                    "taxable": {
                      "type": "boolean",
                      "description": "Whether the item is taxable"
                    },
                    "optional": {
                      "type": "boolean",
                      "description": "Whether the item is optional"
                    }
                  },
                  "required": [
                    "_type",
                    "name",
                    "unit_price"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "image"
                    },
                    "image_path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Storage path returned by a prior `upload_file` call. Upload with module_type=\"workspace\", category=\"line_item\", is_public=true to get a usable path."
                    },
                    "image_id": {
                      "type": "integer",
                      "description": "Upload link ID (`id`) returned by the same `upload_file` call."
                    },
                    "description": {
                      "type": "string",
                      "description": "Caption shown beneath the image in the line items list."
                    }
                  },
                  "required": [
                    "_type",
                    "image_path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Array of line item objects. Two shapes are accepted: a regular priced row (`{ name, quantity, unit_price }`) or an inline image row (`{ _type: \"image\", image_path, image_id, description }`). For image rows: first call `upload_file` with `module_type=\"workspace\"`, `category=\"line_item\"`, `is_public=true` to upload the image, then pass the returned `path` as `image_path` and `id` as `image_id`."
          },
          "discount": {
            "type": "number",
            "description": "Discount amount (default: 0)"
          },
          "discount_unit": {
            "type": "string",
            "enum": [
              "percent",
              "amount"
            ],
            "description": "How the discount is expressed. One of: 'percent' (a percentage of the subtotal) or 'amount' (a fixed currency amount). Default: 'percent'."
          },
          "deposit": {
            "type": "number",
            "description": "Deposit amount (default: 0)"
          },
          "deposit_unit": {
            "$ref": "#/properties/discount_unit",
            "description": "How the deposit is expressed. One of: 'percent' or 'amount'. Default: 'percent'."
          },
          "tax_rate": {
            "type": "number",
            "description": "Tax rate percentage (default: 0)"
          },
          "tax_rate_id": {
            "$ref": "#/properties/contact_id",
            "description": "Tax rate preset ID"
          },
          "total": {
            "type": "number",
            "description": "Invoice total"
          },
          "reminders_enabled": {
            "type": "boolean",
            "description": "Whether BlueSuite automatically emails the client reminders about this invoice. Default: true."
          },
          "waive_credit_card_fee": {
            "$ref": "#/properties/reminders_enabled",
            "description": "Skip the workspace's online processing fee for this record. Only meaningful when the workspace passes processing fees on to clients. Default: false."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "sent",
              "paid",
              "overdue",
              "cancelled",
              "partially_paid",
              "scheduled"
            ],
            "description": "Invoice status (default: draft). Record payments with create_payment; paid is rejected while a balance remains."
          },
          "type": {
            "type": "string",
            "enum": [
              "one-off",
              "recurring"
            ],
            "description": "Invoice type. Only 'one-off' can be created — recurring invoices are no longer supported. For work that repeats, use setup_recurring_job instead; each completed visit bills as its own invoice."
          },
          "event_ids": {
            "type": "array",
            "items": {
              "$ref": "#/properties/contact_id"
            },
            "description": "Event IDs to associate with this invoice"
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_invoice",
      "description": "Get a single invoice by ID with expanded details, including the payments recorded against it and `amount_due` — what the client still owes. Use `amount_due` for balance questions rather than subtracting from `total` yourself; it is derived from the line items, and the stored `total` can be stale.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Invoice ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_invoice",
      "description": "Update an existing invoice",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Invoice ID"
          },
          "name": {
            "type": "string",
            "description": "Invoice name/title"
          },
          "contact_id": {
            "$ref": "#/properties/id",
            "description": "Associated contact ID"
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated property ID"
          },
          "job_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated job ID"
          },
          "quote_id": {
            "$ref": "#/properties/contact_id",
            "description": "Associated quote ID"
          },
          "salesperson_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of salesperson. Use list_users to resolve names."
          },
          "date": {
            "type": "string",
            "description": "Invoice date (YYYY-MM-DD)"
          },
          "due_date": {
            "$ref": "#/properties/date",
            "description": "Due date (YYYY-MM-DD)"
          },
          "send_on": {
            "$ref": "#/properties/date",
            "description": "Scheduled send date (YYYY-MM-DD)"
          },
          "message": {
            "type": "string",
            "description": "Message to client"
          },
          "payment_terms": {
            "type": "string",
            "enum": [
              "due_on_receipt",
              "net_7",
              "net_14",
              "net_30",
              "net_60",
              "net_90"
            ],
            "description": "Payment terms"
          },
          "line_items": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "lineItem"
                    },
                    "name": {
                      "type": "string",
                      "description": "Item name"
                    },
                    "description": {
                      "type": "string",
                      "default": "",
                      "description": "Plain text description for this line item. Omit when not needed."
                    },
                    "quantity": {
                      "type": "number",
                      "default": 1,
                      "description": "Quantity"
                    },
                    "unit_price": {
                      "type": "number",
                      "description": "Price per unit"
                    },
                    "taxable": {
                      "type": "boolean",
                      "description": "Whether the item is taxable"
                    },
                    "optional": {
                      "type": "boolean",
                      "description": "Whether the item is optional"
                    }
                  },
                  "required": [
                    "_type",
                    "name",
                    "unit_price"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "_type": {
                      "type": "string",
                      "const": "image"
                    },
                    "image_path": {
                      "type": "string",
                      "minLength": 1,
                      "description": "Storage path returned by a prior `upload_file` call. Upload with module_type=\"workspace\", category=\"line_item\", is_public=true to get a usable path."
                    },
                    "image_id": {
                      "type": "integer",
                      "description": "Upload link ID (`id`) returned by the same `upload_file` call."
                    },
                    "description": {
                      "type": "string",
                      "description": "Caption shown beneath the image in the line items list."
                    }
                  },
                  "required": [
                    "_type",
                    "image_path"
                  ],
                  "additionalProperties": false
                }
              ]
            },
            "description": "Array of line item objects. Two shapes are accepted: a regular priced row (`{ name, quantity, unit_price }`) or an inline image row (`{ _type: \"image\", image_path, image_id, description }`). For image rows: first call `upload_file` with `module_type=\"workspace\"`, `category=\"line_item\"`, `is_public=true` to upload the image, then pass the returned `path` as `image_path` and `id` as `image_id`."
          },
          "discount": {
            "type": "number",
            "description": "Discount amount"
          },
          "discount_unit": {
            "type": "string",
            "enum": [
              "percent",
              "amount"
            ],
            "description": "How the discount is expressed. One of: 'percent' (a percentage of the subtotal) or 'amount' (a fixed currency amount)."
          },
          "deposit": {
            "type": "number",
            "description": "Deposit amount"
          },
          "deposit_unit": {
            "$ref": "#/properties/discount_unit",
            "description": "How the deposit is expressed. One of: 'percent' or 'amount'."
          },
          "tax_rate": {
            "type": "number",
            "description": "Tax rate percentage"
          },
          "tax_rate_id": {
            "$ref": "#/properties/contact_id",
            "description": "Tax rate preset ID"
          },
          "total": {
            "type": "number",
            "description": "Invoice total"
          },
          "reminders_enabled": {
            "type": "boolean",
            "description": "Whether BlueSuite automatically emails the client reminders about this invoice. Default: true."
          },
          "waive_credit_card_fee": {
            "$ref": "#/properties/reminders_enabled",
            "description": "Skip the workspace's online processing fee for this record. Only meaningful when the workspace passes processing fees on to clients. Default: false."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "sent",
              "paid",
              "overdue",
              "cancelled",
              "partially_paid",
              "scheduled"
            ],
            "description": "Invoice status. To mark paid, record a payment using create_payment with settle_remaining=true."
          },
          "type": {
            "type": "string",
            "enum": [
              "one-off",
              "recurring"
            ],
            "description": "Invoice type"
          },
          "event_ids": {
            "type": "array",
            "items": {
              "$ref": "#/properties/contact_id"
            },
            "description": "Event IDs to associate"
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": {},
            "description": "Custom field values"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_invoice",
      "description": "Delete an invoice by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Invoice ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_invoice_status",
      "description": "Record a change to an invoice's status. This does NOT email anyone — marking an invoice \"sent\" sets its due date and notifies the business internally, but the client receives nothing. To actually deliver an invoice to the client, use send_notification with type=\"invoice_to_customer\", which emails and texts the client according to the workspace notification settings and moves the invoice to sent. Use this tool for cancelling an invoice or correcting a status. To mark an invoice paid, use create_payment with object_type=\"invoice\", category=\"payment\", and settle_remaining=true. A paid status update is rejected if the invoice still has an outstanding balance.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Invoice ID"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "sent",
              "paid",
              "overdue",
              "cancelled",
              "partially_paid",
              "scheduled"
            ],
            "description": "New status"
          }
        },
        "required": [
          "id",
          "status"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_events",
      "description": "List events (appointments, tasks, visits) with optional pagination, search, and filters",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search events"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "name",
              "status",
              "type",
              "start_date",
              "end_date",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "start_date": {
            "type": "string",
            "description": "Filter: start date (YYYY-MM-DD)"
          },
          "end_date": {
            "$ref": "#/properties/start_date",
            "description": "Filter: end date (YYYY-MM-DD)"
          },
          "job_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Filter by job ID"
          },
          "type": {
            "type": "string",
            "enum": [
              "appointment",
              "task",
              "event"
            ],
            "description": "Filter by event type"
          },
          "assignee_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by assignee UUIDs. Use list_users to resolve names to UUIDs."
          },
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "pending",
                "in_progress",
                "scheduled",
                "cancelled",
                "missed",
                "completed"
              ]
            },
            "description": "Filter by one or more statuses."
          },
          "request_id": {
            "$ref": "#/properties/job_id",
            "description": "Filter by request ID"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_event",
      "description": "Create a new event. Three kinds: an APPOINTMENT is a visit for an existing job or request, a TASK is a to-do on the calendar, an EVENT is a standalone calendar entry. Recurrence (recurrence_type=\"recurring\") applies to tasks and events only — appointments cannot repeat on their own. For repeating visits, put the job on a recurring schedule with setup_recurring_job, which also sets the job type and billing settings.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Event name/title"
          },
          "description": {
            "type": "string",
            "description": "Event description"
          },
          "job_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Associated job ID"
          },
          "request_id": {
            "$ref": "#/properties/job_id",
            "description": "Associated request ID"
          },
          "start_date": {
            "type": "string",
            "description": "Start date (YYYY-MM-DD)"
          },
          "end_date": {
            "$ref": "#/properties/start_date",
            "description": "End date (YYYY-MM-DD)"
          },
          "start_time": {
            "type": "string",
            "description": "Start time (HH:MM) in workspace timezone. Required for timed events; omit only for all_day=true or an update retaining the saved time."
          },
          "end_time": {
            "$ref": "#/properties/start_time",
            "description": "End time (HH:MM) in workspace timezone, after the start. Required for timed events; omit only for all_day=true or an update retaining the saved time."
          },
          "all_day": {
            "type": "boolean",
            "description": "Whether this is an all-day event (default: false)"
          },
          "multi_day": {
            "$ref": "#/properties/all_day",
            "description": "Whether this spans multiple days (default: false)"
          },
          "type": {
            "type": "string",
            "enum": [
              "appointment",
              "task",
              "event"
            ],
            "description": "Event type (default: event)"
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "cancelled",
              "missed",
              "completed"
            ],
            "description": "Event status (default: scheduled)"
          },
          "is_flexible": {
            "$ref": "#/properties/all_day",
            "description": "Whether the visit can be moved within the day by scheduling."
          },
          "duration_minutes": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Expected length of the visit in minutes."
          },
          "recurrence_type": {
            "type": "string",
            "enum": [
              "single",
              "recurring"
            ],
            "description": "Set to 'recurring' for a repeating task or standalone event. Default: 'single'. NOT valid for type='appointment' — repeating visits come from setup_recurring_job. The repeat_* fields below only apply when this is 'recurring'."
          },
          "repeat_frequency": {
            "$ref": "#/properties/duration_minutes",
            "description": "Interval between occurrences, used when repeat_frequency_unit is 'custom' (e.g. 2 with a custom weekly unit means every 2 weeks)."
          },
          "repeat_frequency_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How often it repeats: daily, weekly, monthly, yearly, or 'custom' to combine repeat_frequency with repeat_frequency_unit_custom. Default: weekly."
          },
          "repeat_frequency_unit_custom": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "The unit the custom interval counts in. Only used when repeat_frequency_unit is 'custom'."
          },
          "repeat_frequency_schedule": {
            "type": "object",
            "properties": {
              "days": {
                "type": "array",
                "items": {
                  "$ref": "#/properties/duration_minutes"
                },
                "description": "Days to repeat on: 1-7 for weekdays, 1-31 for days of the month."
              },
              "type": {
                "type": "string",
                "enum": [
                  "weekDays",
                  "monthWeekDays",
                  "monthDays"
                ]
              }
            },
            "required": [
              "days",
              "type"
            ],
            "additionalProperties": false,
            "description": "Which days a custom weekly or monthly pattern lands on. Required for those patterns."
          },
          "repeat_duration": {
            "$ref": "#/properties/duration_minutes",
            "description": "How long the series runs. With repeat_duration_unit='occurrences' this is a visit count. Required unless the series repeats forever."
          },
          "repeat_duration_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How the series ends: 'forever' (no end), 'occurrences' (a fixed number of visits, set in repeat_duration), or a time unit. Default: forever."
          },
          "assignee_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Array of assignee UUIDs. Use list_users to resolve names."
          }
        },
        "required": [
          "start_date",
          "end_date"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_event",
      "description": "Get a single event by ID with expanded details",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Event ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_event",
      "description": "Update an existing event. For an occurrence of a recurring appointment, set update_scope to say whether the change applies to just this visit, all future visits, or should rebuild the upcoming schedule.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Event ID"
          },
          "name": {
            "type": "string",
            "description": "Event name/title"
          },
          "description": {
            "type": "string",
            "description": "Event description"
          },
          "job_id": {
            "$ref": "#/properties/id",
            "description": "Associated job ID"
          },
          "request_id": {
            "$ref": "#/properties/job_id",
            "description": "Associated request ID"
          },
          "start_date": {
            "type": "string",
            "description": "Start date (YYYY-MM-DD)"
          },
          "end_date": {
            "$ref": "#/properties/start_date",
            "description": "End date (YYYY-MM-DD)"
          },
          "start_time": {
            "type": "string",
            "description": "Start time (HH:MM) in workspace timezone. Required for timed events; omit only for all_day=true or an update retaining the saved time."
          },
          "end_time": {
            "$ref": "#/properties/start_time",
            "description": "End time (HH:MM) in workspace timezone, after the start. Required for timed events; omit only for all_day=true or an update retaining the saved time."
          },
          "all_day": {
            "type": "boolean",
            "description": "Whether this is an all-day event"
          },
          "multi_day": {
            "$ref": "#/properties/all_day",
            "description": "Whether this spans multiple days"
          },
          "type": {
            "type": "string",
            "enum": [
              "appointment",
              "task",
              "event"
            ],
            "description": "Event type"
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "cancelled",
              "missed",
              "completed"
            ],
            "description": "Event status"
          },
          "is_flexible": {
            "$ref": "#/properties/all_day",
            "description": "Whether the visit can be moved within the day by scheduling."
          },
          "duration_minutes": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Expected length of the visit in minutes."
          },
          "recurrence_type": {
            "type": "string",
            "enum": [
              "single",
              "recurring"
            ],
            "description": "Set to 'recurring' for a repeating task or standalone event. Default: 'single'. NOT valid for type='appointment' — repeating visits come from setup_recurring_job. The repeat_* fields below only apply when this is 'recurring'."
          },
          "repeat_frequency": {
            "$ref": "#/properties/duration_minutes",
            "description": "Interval between occurrences, used when repeat_frequency_unit is 'custom' (e.g. 2 with a custom weekly unit means every 2 weeks)."
          },
          "repeat_frequency_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How often it repeats: daily, weekly, monthly, yearly, or 'custom' to combine repeat_frequency with repeat_frequency_unit_custom. Default: weekly."
          },
          "repeat_frequency_unit_custom": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "The unit the custom interval counts in. Only used when repeat_frequency_unit is 'custom'."
          },
          "repeat_frequency_schedule": {
            "type": "object",
            "properties": {
              "days": {
                "type": "array",
                "items": {
                  "$ref": "#/properties/duration_minutes"
                },
                "description": "Days to repeat on: 1-7 for weekdays, 1-31 for days of the month."
              },
              "type": {
                "type": "string",
                "enum": [
                  "weekDays",
                  "monthWeekDays",
                  "monthDays"
                ]
              }
            },
            "required": [
              "days",
              "type"
            ],
            "additionalProperties": false,
            "description": "Which days a custom weekly or monthly pattern lands on. Required for those patterns."
          },
          "repeat_duration": {
            "$ref": "#/properties/duration_minutes",
            "description": "How long the series runs. With repeat_duration_unit='occurrences' this is a visit count. Required unless the series repeats forever."
          },
          "repeat_duration_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom",
              "forever",
              "occurrences"
            ],
            "description": "How the series ends: 'forever' (no end), 'occurrences' (a fixed number of visits, set in repeat_duration), or a time unit. Default: forever."
          },
          "update_scope": {
            "type": "string",
            "enum": [
              "single",
              "all",
              "recreate"
            ],
            "description": "Which occurrences of a recurring appointment this update touches. 'single' changes only this visit, 'all' applies to this and future visits, 'recreate' rebuilds the upcoming schedule after a pattern change. Default: single. Ask the user which they mean rather than guessing."
          },
          "assignee_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Array of assignee UUIDs. Use list_users to resolve names."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "set_visit_line_items",
      "description": "Set the line items for ONE visit of a job, so that visit bills differently from the rest — the parts used on this trip, an extra callout. When the appointment is completed, its invoice is built from these instead of the job's line items; discount, tax and deposit still come from the job. Send line_items as null to clear the override and bill from the job again. This affects only the single visit, never the whole recurring schedule.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "The appointment (visit) to price."
          },
          "line_items": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "_type": {
                          "type": "string",
                          "const": "lineItem"
                        },
                        "name": {
                          "type": "string",
                          "description": "Item name"
                        },
                        "description": {
                          "type": "string",
                          "default": "",
                          "description": "Plain text description for this line item. Omit when not needed."
                        },
                        "quantity": {
                          "type": "number",
                          "default": 1,
                          "description": "Quantity"
                        },
                        "unit_price": {
                          "type": "number",
                          "description": "Price per unit"
                        },
                        "taxable": {
                          "type": "boolean",
                          "description": "Whether the item is taxable"
                        },
                        "optional": {
                          "type": "boolean",
                          "description": "Whether the item is optional"
                        }
                      },
                      "required": [
                        "_type",
                        "name",
                        "unit_price"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "object",
                      "properties": {
                        "_type": {
                          "type": "string",
                          "const": "image"
                        },
                        "image_path": {
                          "type": "string",
                          "minLength": 1,
                          "description": "Storage path returned by a prior `upload_file` call. Upload with module_type=\"workspace\", category=\"line_item\", is_public=true to get a usable path."
                        },
                        "image_id": {
                          "type": "integer",
                          "description": "Upload link ID (`id`) returned by the same `upload_file` call."
                        },
                        "description": {
                          "type": "string",
                          "description": "Caption shown beneath the image in the line items list."
                        }
                      },
                      "required": [
                        "_type",
                        "image_path"
                      ],
                      "additionalProperties": false
                    }
                  ]
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Line items for this visit only, or null to go back to billing from the job."
          }
        },
        "required": [
          "event_id",
          "line_items"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_event",
      "description": "Delete an event by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Event ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_event_status",
      "description": "Update only the status of an event. Use this instead of update_event when changing status, as status transitions may trigger business logic.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Event ID"
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "cancelled",
              "missed",
              "completed"
            ],
            "description": "New status"
          }
        },
        "required": [
          "id",
          "status"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_timesheets",
      "description": "List timesheets with optional pagination and filters",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search timesheets"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "status",
              "start_date",
              "end_date",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "start_date": {
            "type": "string",
            "description": "Filter: start date (YYYY-MM-DD)"
          },
          "end_date": {
            "$ref": "#/properties/start_date",
            "description": "Filter: end date (YYYY-MM-DD)"
          },
          "user_id": {
            "type": "string",
            "format": "uuid",
            "description": "Filter by user UUID. Use list_users to resolve names."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "pending",
              "approved",
              "rejected"
            ],
            "description": "Filter by status"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_timesheet",
      "description": "Get a single timesheet by ID with expanded details",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Timesheet ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_timesheet_status",
      "description": "Update only the status of a timesheet. Use this for approval workflows (draft → pending → approved/rejected).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Timesheet ID"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "pending",
              "approved",
              "rejected"
            ],
            "description": "New status"
          }
        },
        "required": [
          "id",
          "status"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_time_entries",
      "description": "List time entries with optional pagination and filters",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search time entries"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "start_date",
              "end_date",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "start_date": {
            "type": "string",
            "description": "Filter: start date (YYYY-MM-DD)"
          },
          "end_date": {
            "$ref": "#/properties/start_date",
            "description": "Filter: end date (YYYY-MM-DD)"
          },
          "user_id": {
            "type": "string",
            "format": "uuid",
            "description": "Filter by user UUID. Use list_users to resolve names."
          },
          "job_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Filter by job ID"
          },
          "request_id": {
            "$ref": "#/properties/job_id",
            "description": "Filter by request ID"
          },
          "quote_id": {
            "$ref": "#/properties/job_id",
            "description": "Filter by quote ID"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_time_entry",
      "description": "Log time against a job, quote, request or service plan. Durations are in MINUTES — record two hours as 120, not 2. Defaults to the signed-in user; pass user_id to log time for a crew member.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "start_date": {
            "type": "string",
            "description": "Start date (YYYY-MM-DD)"
          },
          "end_date": {
            "$ref": "#/properties/start_date",
            "description": "End date (YYYY-MM-DD)"
          },
          "start_time": {
            "type": "string",
            "description": "Start time (HH:MM)"
          },
          "end_time": {
            "$ref": "#/properties/start_time",
            "description": "End time (HH:MM)"
          },
          "total_time": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Duration in MINUTES, not hours — a two hour visit is 120. Max 1440 (one day). Either give this, or give start_time and end_time."
          },
          "description": {
            "type": "string",
            "description": "Description of work done"
          },
          "user_id": {
            "type": "string",
            "format": "uuid",
            "description": "Whose time this is. Defaults to the signed-in user. Use list_users to resolve a name; the user must be a member of this workspace."
          },
          "job_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Associated job ID"
          },
          "request_id": {
            "$ref": "#/properties/job_id",
            "description": "Associated request ID"
          },
          "quote_id": {
            "$ref": "#/properties/job_id",
            "description": "Associated quote ID"
          }
        },
        "required": [
          "start_date",
          "end_date"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_time_entry",
      "description": "Update an existing time entry",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Time entry ID"
          },
          "start_date": {
            "type": "string",
            "description": "Start date (YYYY-MM-DD)"
          },
          "end_date": {
            "$ref": "#/properties/start_date",
            "description": "End date (YYYY-MM-DD)"
          },
          "start_time": {
            "type": "string",
            "description": "Start time (HH:MM)"
          },
          "end_time": {
            "$ref": "#/properties/start_time",
            "description": "End time (HH:MM)"
          },
          "total_time": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Duration in MINUTES, not hours — two hours is 120. Max 1440."
          },
          "description": {
            "type": "string",
            "description": "Description of work done"
          },
          "user_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the user. Use list_users to resolve names."
          },
          "job_id": {
            "anyOf": [
              {
                "$ref": "#/properties/id"
              },
              {
                "type": "null"
              }
            ],
            "description": "Associated job ID"
          },
          "request_id": {
            "anyOf": [
              {
                "$ref": "#/properties/job_id/anyOf/0"
              },
              {
                "type": "null"
              }
            ],
            "description": "Associated request ID"
          },
          "quote_id": {
            "anyOf": [
              {
                "$ref": "#/properties/job_id/anyOf/0"
              },
              {
                "type": "null"
              }
            ],
            "description": "Associated quote ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_time_entry",
      "description": "Delete a time entry by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Time entry ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_users",
      "description": "List workspace team members. Use this to resolve user names to IDs for assignment operations (e.g., assigning a job to \"Bob\").",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search by name, email, phone, or company"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "first_name",
              "last_name",
              "email",
              "role",
              "job_title",
              "created_at",
              "updated_at"
            ],
            "description": "Field to sort by. There is no \"name\" field — use first_name or last_name. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_services",
      "description": "List saved products and services. These are reusable line items that can be added to quotes, jobs, and invoices.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search by name or description"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "name",
              "price",
              "sku",
              "type",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "id_in": {
            "type": "array",
            "items": {
              "type": "integer",
              "exclusiveMinimum": 0
            },
            "description": "Filter by a specific list of service IDs."
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_service",
      "description": "Create a new saved product or service. Once created, it can be used as a line item on quotes, jobs, and invoices.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "Service/product name"
          },
          "description": {
            "type": "string",
            "description": "Plain text description of the service or product. Omit when not needed."
          },
          "price": {
            "type": "number",
            "description": "Default price (default: 0)"
          },
          "sku": {
            "type": "string",
            "description": "Free-form SKU or product code string. Omit when not needed."
          },
          "type": {
            "type": "string",
            "enum": [
              "service",
              "product"
            ],
            "description": "Type: service or product (default: service)"
          },
          "taxable": {
            "type": "boolean",
            "description": "Whether this item is taxable (default: true)"
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_service",
      "description": "Get a single product or service by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Service ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_service",
      "description": "Update an existing product or service",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Service ID"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "Service/product name"
          },
          "description": {
            "type": "string",
            "description": "Plain text description of the service or product."
          },
          "price": {
            "type": "number",
            "description": "Default price"
          },
          "sku": {
            "type": "string",
            "description": "Free-form SKU or product code string."
          },
          "type": {
            "type": "string",
            "enum": [
              "service",
              "product"
            ],
            "description": "Type: service or product"
          },
          "taxable": {
            "type": "boolean",
            "description": "Whether this item is taxable"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_service",
      "description": "Delete a product or service by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Service ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_service_plans",
      "description": "List the recurring service plans the business offers — maintenance agreements, seasonal packages. These are templates customers subscribe to, not the subscriptions themselves.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "draft",
                "active",
                "archived"
              ]
            },
            "description": "Filter by draft, active or archived."
          },
          "search": {
            "type": "string",
            "description": "Search by plan name."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_service_plan",
      "description": "Get one service plan with its pricing, billing cycle and visit schedule.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Service plan ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_service_plan",
      "description": "Create a recurring service plan customers can subscribe to. This defines the offer — price, how often it bills, how often visits happen — and bills nobody by itself. New plans start as drafts; publish with update_service_plan_status. Note billing cycle and visit frequency are independent: a plan can bill monthly and visit quarterly.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "e.g. \"Annual HVAC Maintenance\"."
          },
          "description": {
            "type": "string"
          },
          "billing_amount": {
            "type": "number",
            "description": "Charged each billing cycle."
          },
          "billing_cycle": {
            "type": "string",
            "enum": [
              "weekly",
              "monthly",
              "quarterly",
              "semi_annually",
              "annually"
            ],
            "description": "How often the customer is charged. Default: monthly."
          },
          "billing_timing": {
            "type": "string",
            "enum": [
              "start",
              "end"
            ],
            "description": "Charge at the 'start' or 'end' of each cycle. Default: start."
          },
          "duration_type": {
            "type": "string",
            "enum": [
              "until_cancelled",
              "fixed_end_date"
            ],
            "description": "'until_cancelled' or 'fixed_end_date'. Default: until_cancelled."
          },
          "duration_end_date": {
            "type": "string",
            "description": "Required when duration_type is 'fixed_end_date' (YYYY-MM-DD)."
          },
          "visit_recurrence_frequency": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "How many visit_recurrence_units between visits. Default: 1."
          },
          "visit_recurrence_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom"
            ],
            "description": "Unit for the visit schedule. Default: monthly."
          },
          "no_appointments": {
            "type": "boolean",
            "description": "A billing-only plan: subscribers are charged but no visits are booked."
          },
          "tax_rate": {
            "type": "number"
          },
          "tax_rate_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Tax rate preset ID."
          },
          "terms": {
            "type": "string",
            "description": "Terms shown to the customer."
          },
          "default_account_manager_id": {
            "type": "string",
            "description": "UUID of the default account manager. Use list_users to resolve a name."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "active",
              "archived"
            ],
            "description": "Default: draft."
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_service_plan",
      "description": "Update a service plan. Send only what changes — the server merges it over the existing plan. Changing the price affects new subscribers; anyone already subscribed keeps billing at the terms they signed up under, since their charge lives in Stripe.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Service plan ID"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "billing_amount": {
            "type": "number"
          },
          "billing_cycle": {
            "type": "string",
            "enum": [
              "weekly",
              "monthly",
              "quarterly",
              "semi_annually",
              "annually"
            ]
          },
          "billing_timing": {
            "type": "string",
            "enum": [
              "start",
              "end"
            ]
          },
          "duration_type": {
            "type": "string",
            "enum": [
              "until_cancelled",
              "fixed_end_date"
            ]
          },
          "duration_end_date": {
            "type": "string"
          },
          "visit_recurrence_frequency": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "visit_recurrence_unit": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom"
            ]
          },
          "no_appointments": {
            "type": "boolean"
          },
          "tax_rate": {
            "type": "number"
          },
          "tax_rate_id": {
            "$ref": "#/properties/id"
          },
          "terms": {
            "type": "string"
          },
          "default_account_manager_id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID of the default account manager. Use list_users to resolve names."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_service_plan_status",
      "description": "Publish, unpublish or archive a service plan. This is the template's own status: archiving a plan stops new signups but does NOT cancel or stop billing anyone already subscribed to it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Service plan ID"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "active",
              "archived"
            ],
            "description": "draft (not offered), active (open for signups), archived (retired)."
          }
        },
        "required": [
          "id",
          "status"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_service_plan",
      "description": "Delete a service plan. Archive it instead if anyone has ever subscribed — archiving stops new signups and keeps the history.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Service plan ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_service_plan_subscriptions",
      "description": "List customers subscribed to service plans, with their status and billing amount. Use this to answer who is on a plan, who is paused, and who cancelled.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "service_plan_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Only subscribers to this plan."
          },
          "status": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "pending",
                "active",
                "paused",
                "cancelled",
                "expired"
              ]
            },
            "description": "Filter by pending, active, paused, cancelled or expired."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_service_plan_subscription",
      "description": "Get one subscription with its plan, customer, status and billing details.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Subscription ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_service_plan_subscription",
      "description": "Reassign a subscription: which client it belongs to, which property it covers, or who manages the account. Price and billing cadence cannot be changed here — those live on the plan and in Stripe, and editing them in BlueSuite alone would disagree with what the customer is actually charged. There is also no way to CREATE a subscription from here: signing someone up requires collecting a payment method, which has to happen in the dashboard.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Subscription ID"
          },
          "contact_id": {
            "$ref": "#/properties/id",
            "description": "Client the subscription belongs to."
          },
          "property_id": {
            "$ref": "#/properties/contact_id",
            "description": "Property it covers."
          },
          "account_manager_id": {
            "type": "string",
            "description": "UUID of the account manager. Use list_users to resolve a name."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "cancel_service_plan_subscription",
      "description": "Cancel a customer's service plan subscription and stop billing them. This cancels the Stripe subscription first, then marks it cancelled in BlueSuite — doing only the second would leave the customer being charged every cycle. If Stripe refuses, nothing is changed and an error comes back; report that to the user rather than assuming billing stopped. Confirm with the user before calling: this stops a recurring payment.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Subscription ID to cancel."
          },
          "force": {
            "type": "boolean",
            "description": "Mark it cancelled in BlueSuite even if Stripe could not be cancelled. Leaves the customer being billed — only use when the user understands that and asks for it."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": true
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_tax_rates",
      "description": "List tax rate presets for the workspace. These can be applied to quotes, jobs, and invoices.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search by name or description"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "name",
              "rate",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_tax_rate",
      "description": "Create a new tax rate preset. Once created, it can be applied to quotes, jobs, and invoices.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Tax rate name (e.g. \"Sales Tax\", \"VAT\")"
          },
          "description": {
            "type": "string",
            "description": "Description of the tax rate. Omit when not needed."
          },
          "rate": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Tax rate percentage. Pass the percent itself (e.g. 8.25 for 8.25%, not 0.0825). Must be between 0 and 100."
          }
        },
        "required": [
          "name",
          "rate"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_tax_rate",
      "description": "Get a single tax rate preset by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Tax rate ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_tax_rate",
      "description": "Update an existing tax rate preset",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Tax rate ID"
          },
          "name": {
            "type": "string",
            "description": "Tax rate name"
          },
          "description": {
            "type": "string",
            "description": "Description of the tax rate."
          },
          "rate": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Tax rate percentage. Pass the percent itself (e.g. 8.25 for 8.25%, not 0.0825). Must be between 0 and 100."
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_tax_rate",
      "description": "Delete a tax rate preset by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Tax rate ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_workspace",
      "description": "Get basic information about the current BlueSuite workspace — name, industry, country, currency, timezone, and about blurb. Use this when the user asks about their business or workspace.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "upload_file",
      "description": "Attach a file (receipt, photo, PDF, document, video, audio) to a parent entity (contact, request, quote, job, invoice, event, or timesheet). Also used to upload line item images: pass `module_type=\"workspace\"`, `module_id` = workspace ID (call `get_workspace` first if needed), `category=\"line_item\"`, `is_public=true`, then use the returned `path` and `id` as `image_path`/`image_id` in a quote/invoice/job line item. Provide the file via `file` (a user-attached file from the chat — preferred when available), `source_url` (a URL to fetch), or `base64_data` (raw bytes). Max file size is 100 MB. Allowed MIME types: image/jpeg, image/png, image/webp, image/gif, image/avif, application/pdf, Word/Excel/PowerPoint docs, CSV, plain text, video (mp4/avi/mov), audio (aac/mp3/wav).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "module_type": {
            "type": "string",
            "enum": [
              "contact",
              "request",
              "quote",
              "job",
              "invoice",
              "event",
              "timesheet",
              "workspace"
            ],
            "description": "Parent entity type. Use \"workspace\" only when paired with category=\"line_item\" for line item images."
          },
          "module_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "ID of the parent entity in the current workspace. For module_type=\"workspace\", pass the workspace ID itself."
          },
          "file": {
            "type": "object",
            "properties": {
              "download_url": {
                "type": "string",
                "format": "uri",
                "description": "HTTPS URL the server can fetch the file bytes from."
              },
              "file_id": {
                "type": "string",
                "description": "Opaque file identifier from the host."
              },
              "file_name": {
                "type": "string",
                "description": "Original filename, if the host provides it."
              },
              "mime_type": {
                "type": "string",
                "description": "MIME type hint from the host. Validated against the server allowlist after fetch."
              }
            },
            "required": [
              "download_url",
              "file_id"
            ],
            "additionalProperties": true,
            "description": "A file attached by the user in the chat. Preferred over source_url/base64_data when the host populates it. Extra fields injected by the host are ignored."
          },
          "source_url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS URL to fetch the file from. Use when you have a public URL but no chat-attached file."
          },
          "base64_data": {
            "type": "string",
            "description": "Base64-encoded file bytes. Use only when neither `file` nor `source_url` is available. When using this, mime_type and file_name are required."
          },
          "mime_type": {
            "type": "string",
            "enum": [
              "image/jpeg",
              "image/jpg",
              "image/png",
              "image/webp",
              "image/gif",
              "image/avif",
              "image/heic",
              "image/heif",
              "application/pdf",
              "application/msword",
              "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
              "text/csv",
              "text/plain",
              "application/vnd.ms-excel",
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
              "application/vnd.ms-powerpoint",
              "application/vnd.openxmlformats-officedocument.presentationml.presentation",
              "video/mp4",
              "video/x-msvideo",
              "video/avi",
              "video/quicktime",
              "audio/aac",
              "audio/mpeg",
              "audio/wav"
            ],
            "description": "MIME type of the file. Required with base64_data; with file/source_url, falls back to the response Content-Type. Must be one of the accepted upload types."
          },
          "file_name": {
            "type": "string",
            "description": "Original filename. Required with base64_data; with file/source_url, derived from the URL path."
          },
          "category": {
            "type": "string",
            "enum": [
              "attachment",
              "internal",
              "public",
              "expense",
              "line_item"
            ],
            "description": "How the file should be tagged. Defaults to \"attachment\". Use \"expense\" for receipts on jobs. Use \"line_item\" (only with module_type=\"workspace\") for line item images."
          },
          "name": {
            "type": "string",
            "description": "Display name for the link. Defaults to the file name."
          },
          "description": {
            "type": "string",
            "description": "Optional description shown alongside the file."
          },
          "is_public": {
            "type": "boolean",
            "description": "When true, the file is stored in the public bucket and gets a permanent unauthenticated URL. Default: false (private bucket, signed URLs that expire)."
          }
        },
        "required": [
          "module_type",
          "module_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "execution": {
        "taskSupport": "forbidden"
      },
      "_meta": {
        "openai/fileParams": [
          "file"
        ]
      }
    },
    {
      "name": "list_files",
      "description": "List files attached to a parent entity (contact, request, quote, job, invoice, event, or timesheet). Returns paginated upload links with fresh signed URLs.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "module_type": {
            "type": "string",
            "enum": [
              "contact",
              "request",
              "quote",
              "job",
              "invoice",
              "event",
              "timesheet",
              "workspace"
            ],
            "description": "Parent entity type."
          },
          "module_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Parent entity ID."
          },
          "category": {
            "type": "string",
            "enum": [
              "attachment",
              "internal",
              "public",
              "expense",
              "line_item"
            ],
            "description": "Filter by category (e.g. only \"expense\" receipts)."
          },
          "page": {
            "$ref": "#/properties/module_id",
            "description": "Page number (default: 1)."
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25, max 100)."
          }
        },
        "required": [
          "module_type",
          "module_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_upload",
      "description": "Get a single upload link with a fresh signed URL. The link_id is the ID returned by upload_file or list_files.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "link_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Upload link ID."
          }
        },
        "required": [
          "link_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_upload",
      "description": "Update the name, description, or category of an existing upload link. The underlying file bytes cannot be replaced — delete the link and re-upload to change the file itself.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "link_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Upload link ID."
          },
          "name": {
            "type": "string",
            "description": "New display name."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "New description (or null to clear)."
          },
          "category": {
            "type": "string",
            "enum": [
              "attachment",
              "internal",
              "public",
              "expense",
              "line_item"
            ],
            "description": "New category."
          }
        },
        "required": [
          "link_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_upload",
      "description": "Remove a file attachment from its parent entity. If the underlying file is not linked to any other entity, the file is also permanently deleted from storage.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "link_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Upload link ID."
          }
        },
        "required": [
          "link_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "send_notification",
      "description": "Send a transactional customer-facing notification (email + SMS where configured).\nUse this to send a quote to a customer, send an invoice, or send an appointment reminder.\nThe \"type\" determines both the message template and the target module: quote_to_customer→quotes, invoice_to_customer→invoices, appointment_reminder→events. \"module_id\" is the ID of that parent entity.\nChannel selection (email vs SMS) is automatic — it follows the workspace customer-notification settings and the contact's SMS opt-in. Email goes through AWS SES; SMS through Twilio.\nSet reminder=true for quote_to_customer or invoice_to_customer to send a \"(Reminder)\" prefixed message with reminder-friendly language instead of the initial send. Reminders do NOT change entity status.\nWithout reminder (or reminder=false), invoice_to_customer transitions the invoice status to \"sent\" and quote_to_customer transitions to \"awaiting_response\".\nDoes not currently support arbitrary internal messages to workspace users.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "quote_to_customer",
              "invoice_to_customer",
              "appointment_reminder"
            ],
            "description": "Notification type. quote_to_customer sends a quote (module_id is a quote ID), invoice_to_customer sends an invoice (module_id is an invoice ID), appointment_reminder sends a reminder (module_id is an event ID)."
          },
          "module_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "ID of the parent entity (quote, invoice, or event — see \"type\")."
          },
          "reminder": {
            "type": "boolean",
            "description": "Set to true to send a reminder instead of an initial notification. Adds \"(Reminder)\" prefix to the subject and uses friendlier reminder language. Does not change entity status. Only applies to quote_to_customer and invoice_to_customer."
          }
        },
        "required": [
          "type",
          "module_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_comment",
      "description": "Post an internal comment on a parent entity (contact, request, quote, job, invoice, event, or timesheet).\nComments are not customer-facing — they show up in the dashboard's activity panel for the parent.\nOptionally @-mention workspace members (each gets a comments_mention notification) and/or reply to an existing comment (the original author gets a comments_reply notification).\nFor quote/job/invoice/request comments, the parent entity's creator also receives a comments_new notification (skipped if they're already covered by mention/reply dedup or if they wrote this comment).\nThe comment author is the user who created the API key.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "module_type": {
            "type": "string",
            "enum": [
              "contact",
              "request",
              "quote",
              "job",
              "invoice",
              "event",
              "timesheet"
            ],
            "description": "Parent entity type."
          },
          "module_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "ID of the parent entity in the current workspace."
          },
          "comment": {
            "type": "string",
            "minLength": 1,
            "maxLength": 10000,
            "description": "Comment body (1 to 10,000 characters)."
          },
          "mentioned_user_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "maxItems": 50,
            "description": "UUIDs of workspace members to @-mention. Each receives a comments_mention notification. Use list_users to resolve names to UUIDs."
          },
          "reply_to": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "ID of an existing comment to reply to. The parent comment's author receives a comments_reply notification."
          }
        },
        "required": [
          "module_type",
          "module_id",
          "comment"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_comments",
      "description": "List internal comments attached to a parent entity (contact, request, quote, job, invoice, event, or timesheet). Returns paginated comments newest-first; soft-deleted comments are excluded.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "module_type": {
            "type": "string",
            "enum": [
              "contact",
              "request",
              "quote",
              "job",
              "invoice",
              "event",
              "timesheet"
            ],
            "description": "Parent entity type."
          },
          "module_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Parent entity ID."
          },
          "page": {
            "$ref": "#/properties/module_id",
            "description": "Page number (default: 1)."
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25, max 100)."
          }
        },
        "required": [
          "module_type",
          "module_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_comment",
      "description": "Get a single comment by ID, including the joined author profile.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "comment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Comment ID."
          }
        },
        "required": [
          "comment_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_comment",
      "description": "Soft-delete a comment. The row is retained for audit but stops appearing in list responses. Cannot be undone via this API.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "comment_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Comment ID."
          }
        },
        "required": [
          "comment_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_job_expenses",
      "description": "List expenses for a job. Expenses track costs associated with jobs (materials, subcontractors, permits, etc.).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "job_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search by name or description"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "name",
              "total",
              "date",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          }
        },
        "required": [
          "job_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_job_expense",
      "description": "Create a new expense for a job. Expenses track costs such as materials, subcontractor fees, permits, etc. Provide a receipt via `receipt` (a user-attached file from the chat) or `attachment` (a storage path from a prior upload_file call).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "job_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          },
          "name": {
            "type": "string",
            "description": "Expense name/title"
          },
          "description": {
            "type": "string",
            "description": "Expense description. Omit when not needed."
          },
          "date": {
            "type": "string",
            "description": "Expense date (YYYY-MM-DD)"
          },
          "total": {
            "type": "number",
            "description": "Expense amount"
          },
          "receipt": {
            "type": "object",
            "properties": {
              "download_url": {
                "type": "string",
                "format": "uri",
                "description": "HTTPS URL the server can fetch the file bytes from."
              },
              "file_id": {
                "type": "string",
                "description": "Opaque file identifier from the host."
              },
              "file_name": {
                "type": "string",
                "description": "Original filename, if the host provides it."
              },
              "mime_type": {
                "type": "string",
                "description": "MIME type hint from the host. Validated against the server allowlist after fetch."
              }
            },
            "required": [
              "download_url",
              "file_id"
            ],
            "additionalProperties": true,
            "description": "A receipt file attached by the user in the chat. Preferred over `attachment` when the host populates it. The file is uploaded automatically and linked to the expense."
          },
          "attachment": {
            "type": "string",
            "description": "Storage path of an already-uploaded file (from a prior upload_file call). Use only when not providing `receipt`."
          }
        },
        "required": [
          "job_id",
          "name",
          "total"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      },
      "_meta": {
        "openai/fileParams": [
          "receipt"
        ]
      }
    },
    {
      "name": "get_job_expense",
      "description": "Get a single expense by ID for a job",
      "inputSchema": {
        "type": "object",
        "properties": {
          "job_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          },
          "expense_id": {
            "$ref": "#/properties/job_id",
            "description": "Expense ID"
          }
        },
        "required": [
          "job_id",
          "expense_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_job_expense",
      "description": "Update an existing expense for a job. Provide a new receipt via `receipt` (a user-attached file from the chat) or `attachment` (a storage path from a prior upload_file call). Pass `attachment: \"\"` to clear the existing receipt.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "job_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          },
          "expense_id": {
            "$ref": "#/properties/job_id",
            "description": "Expense ID"
          },
          "name": {
            "type": "string",
            "description": "Expense name/title"
          },
          "description": {
            "type": "string",
            "description": "Expense description"
          },
          "date": {
            "type": "string",
            "description": "Expense date (YYYY-MM-DD)"
          },
          "total": {
            "type": "number",
            "description": "Expense amount"
          },
          "receipt": {
            "type": "object",
            "properties": {
              "download_url": {
                "type": "string",
                "format": "uri",
                "description": "HTTPS URL the server can fetch the file bytes from."
              },
              "file_id": {
                "type": "string",
                "description": "Opaque file identifier from the host."
              },
              "file_name": {
                "type": "string",
                "description": "Original filename, if the host provides it."
              },
              "mime_type": {
                "type": "string",
                "description": "MIME type hint from the host. Validated against the server allowlist after fetch."
              }
            },
            "required": [
              "download_url",
              "file_id"
            ],
            "additionalProperties": true,
            "description": "A new receipt file attached by the user in the chat. Replaces any existing receipt. Preferred over `attachment` when the host populates it."
          },
          "attachment": {
            "type": "string",
            "description": "Storage path of an already-uploaded file, or empty string to clear the existing receipt. Use only when not providing `receipt`."
          }
        },
        "required": [
          "job_id",
          "expense_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      },
      "_meta": {
        "openai/fileParams": [
          "receipt"
        ]
      }
    },
    {
      "name": "delete_job_expense",
      "description": "Delete an expense from a job",
      "inputSchema": {
        "type": "object",
        "properties": {
          "job_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Job ID"
          },
          "expense_id": {
            "$ref": "#/properties/job_id",
            "description": "Expense ID"
          }
        },
        "required": [
          "job_id",
          "expense_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_payments",
      "description": "List payments with optional filtering by parent object (invoice/quote), status, and pagination.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "sort_by": {
            "type": "string",
            "enum": [
              "id",
              "amount",
              "status",
              "created_at",
              "modified_at"
            ],
            "description": "Field to sort by. Unknown values fall back to the default sort."
          },
          "sort_direction": {
            "type": "string",
            "enum": [
              "asc",
              "desc"
            ],
            "description": "Sort direction"
          },
          "object_id": {
            "type": "integer",
            "description": "Filter by parent object ID (invoice or quote ID)"
          },
          "object_type": {
            "type": "string",
            "enum": [
              "invoice",
              "quote"
            ],
            "description": "Filter by parent object type: 'invoice' or 'quote'"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "completed",
              "failed",
              "refunded"
            ],
            "description": "Filter by payment status"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_payment",
      "description": "Record money already received against an invoice or quote. For \"mark invoice paid\", set object_type=\"invoice\", category=\"payment\", settle_remaining=true and omit amount. The server records only the outstanding balance, accounting for existing payments and deposits, and then updates the invoice status. Repeating settlement of an already covered balance creates no payment. For a specific partial payment, supply amount. Omitted method defaults to other. Supply created_at only when the user gives a payment date. This records a manual payment; it does not charge a card.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "object_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Parent object ID (invoice or quote ID)"
          },
          "object_type": {
            "type": "string",
            "enum": [
              "invoice",
              "quote"
            ],
            "description": "Parent object type: 'invoice' or 'quote'"
          },
          "category": {
            "type": "string",
            "enum": [
              "deposit",
              "payment"
            ],
            "description": "Payment category: 'deposit' for deposit payments, 'payment' for regular payments"
          },
          "amount": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Amount received for a specific payment. Omit when settle_remaining is true."
          },
          "settle_remaining": {
            "type": "boolean",
            "description": "Set true to mark an invoice paid by recording its remaining balance. Only for completed manual invoice payments, without a tip."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When payment was received, as an ISO timestamp. Use the user-provided date in the workspace timezone; omit if unspecified."
          },
          "tip_amount": {
            "type": "number",
            "minimum": 0,
            "description": "Tip amount (default: 0)"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "completed",
              "failed",
              "refunded"
            ],
            "description": "Payment status (default: 'completed')"
          },
          "gateway": {
            "type": "string",
            "enum": [
              "manual",
              "stripe:connect"
            ],
            "description": "Payment gateway (default: 'manual')"
          },
          "method": {
            "type": "string",
            "enum": [
              "other",
              "credit_card",
              "cash",
              "check",
              "bank_transfer",
              "ach"
            ],
            "description": "Payment method: 'cash', 'check', 'credit_card', 'bank_transfer', 'ach', or 'other' (default: 'other')"
          },
          "notes": {
            "type": "string",
            "description": "Payment notes. Omit when not needed."
          }
        },
        "required": [
          "object_id",
          "object_type",
          "category"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_payment",
      "description": "Get a single payment by ID",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Payment ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_payment",
      "description": "Update an existing payment. Changing amount or status will automatically recalculate the parent object status.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Payment ID"
          },
          "amount": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Payment amount"
          },
          "tip_amount": {
            "type": "number",
            "minimum": 0,
            "description": "Tip amount"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "completed",
              "failed",
              "refunded"
            ],
            "description": "Payment status"
          },
          "method": {
            "type": "string",
            "enum": [
              "other",
              "credit_card",
              "cash",
              "check",
              "bank_transfer",
              "ach"
            ],
            "description": "Payment method"
          },
          "category": {
            "type": "string",
            "enum": [
              "deposit",
              "payment"
            ],
            "description": "Payment category"
          },
          "notes": {
            "type": "string",
            "description": "Payment notes"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_payment",
      "description": "Delete a payment. This will automatically recalculate the parent object status (e.g., invoice may revert from \"paid\" to \"partially_paid\" or \"sent\").",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Payment ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_help_guides",
      "description": "Index of BlueSuite product help articles. Use it to find guides relevant to a user's how-to question before fetching the best match.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "string",
            "description": "The tool's answer as text, meant to be read and relayed."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_help_article",
      "description": "Fetch a BlueSuite product help article by the guide ID returned from list_help_guides. Use its content to answer the user and cite its source link.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Help guide ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "string",
            "description": "The tool's answer as text, meant to be read and relayed."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_tags",
      "description": "List the tags defined for one kind of record. Call this before tagging something, to find the tag IDs and to avoid creating a duplicate of a tag that already exists.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "taggable_type": {
            "type": "string",
            "enum": [
              "request",
              "quote",
              "job",
              "invoice",
              "contact"
            ],
            "description": "Which kind of record the tag belongs to. Tags are scoped per type: a \"Priority\" tag on jobs is a separate tag from a \"Priority\" tag on contacts, so this is always required."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "description": "Results per page (default: 25)"
          },
          "search": {
            "type": "string",
            "description": "Search tags by name"
          }
        },
        "required": [
          "taggable_type"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "create_tag",
      "description": "Create a new tag for one kind of record. Check `list_tags` first — tags are matched by ID, not name, so creating a second \"Urgent\" tag splits the records between them.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Tag name, e.g. \"Urgent\" or \"Needs parts\"."
          },
          "taggable_type": {
            "type": "string",
            "enum": [
              "request",
              "quote",
              "job",
              "invoice",
              "contact"
            ],
            "description": "Which kind of record the tag belongs to. Tags are scoped per type: a \"Priority\" tag on jobs is a separate tag from a \"Priority\" tag on contacts, so this is always required."
          },
          "description": {
            "type": "string",
            "description": "Optional description of what the tag means."
          },
          "color": {
            "type": "string",
            "description": "Hex color such as #3b82f6. Defaults to no color if omitted."
          }
        },
        "required": [
          "name",
          "taggable_type"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "update_tag",
      "description": "Rename a tag, change its color, or edit its description. A tag's record type cannot be changed — create a new tag instead.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Tag ID"
          },
          "name": {
            "type": "string",
            "description": "New tag name"
          },
          "description": {
            "type": "string",
            "description": "New description"
          },
          "color": {
            "type": "string",
            "description": "New hex color, e.g. #ef4444"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "delete_tag",
      "description": "Delete a tag. This removes it from every record it is currently applied to.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Tag ID"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_entity_tags",
      "description": "Get the tags currently applied to one record (a job, quote, invoice, request or contact).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "taggable_type": {
            "type": "string",
            "enum": [
              "request",
              "quote",
              "job",
              "invoice",
              "contact"
            ],
            "description": "Which kind of record the tag belongs to. Tags are scoped per type: a \"Priority\" tag on jobs is a separate tag from a \"Priority\" tag on contacts, so this is always required."
          },
          "taggable_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "ID of the record."
          }
        },
        "required": [
          "taggable_type",
          "taggable_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "set_entity_tags",
      "description": "Set which tags are applied to one record. This REPLACES the record's tags rather than adding to them, so to add a tag you must first call `get_entity_tags` and send the existing tag IDs along with the new one. Sending an empty list clears all tags from the record.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "taggable_type": {
            "type": "string",
            "enum": [
              "request",
              "quote",
              "job",
              "invoice",
              "contact"
            ],
            "description": "Which kind of record the tag belongs to. Tags are scoped per type: a \"Priority\" tag on jobs is a separate tag from a \"Priority\" tag on contacts, so this is always required."
          },
          "taggable_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "ID of the record to tag."
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "$ref": "#/properties/taggable_id"
            },
            "description": "The complete set of tag IDs the record should end up with. Must belong to the same taggable_type. Use list_tags to resolve names to IDs."
          }
        },
        "required": [
          "taggable_type",
          "taggable_id",
          "tag_ids"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "request_review",
      "description": "Ask a client to leave a review. Sends immediately over whichever channels the workspace has turned on (email, SMS) and the client can actually receive. Confirm with the user before calling — this puts a message in front of their customer. Mention the appointment with event_id when the request is about one specific visit: it switches to a message that names the visit and the crew who attended, which lands far better than a generic ask. BlueSuite also asks automatically after jobs complete or invoices are paid if the workspace set that up, so check whether a recent request already went out before adding another.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Client to ask. Use list_contacts to resolve a name first. They need an email address, or a mobile number with SMS consent."
          },
          "event_id": {
            "$ref": "#/properties/contact_id",
            "description": "The appointment this is about. Including it uses the message that names the visit and the crew."
          },
          "invoice_id": {
            "$ref": "#/properties/event_id",
            "description": "The invoice this is about, when the ask follows a payment."
          },
          "ignore_cooldown": {
            "type": "boolean",
            "description": "Ask even if this client was asked recently or has already left a review. Off by default, and the workspace cooldown normally applies. Only set this when the user has said to ask anyway."
          }
        },
        "required": [
          "contact_id"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "anyOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ],
            "description": "The affected record, or the result of the operation. Null when nothing matched."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "list_review_requests",
      "description": "Review requests that have gone out and what came back — star rating, written feedback, and whether the client clicked through to a review platform. Use this to answer how the reviews are going, and to check whether a client has been asked recently before asking again.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Only requests sent to this client."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "completed",
              "expired"
            ],
            "description": "pending (sent, no response yet), completed (the client responded), or expired (the link lapsed)."
          },
          "page": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Page number (default: 1)"
          },
          "per_page": {
            "$ref": "#/properties/page",
            "description": "Results per page (default: 25)"
          }
        },
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            },
            "description": "The matching records for this page."
          },
          "pagination": {
            "type": "object",
            "properties": {
              "page": {
                "type": "integer",
                "description": "Current page number, 1-based."
              },
              "per_page": {
                "type": "integer",
                "description": "Number of results per page."
              },
              "total_pages": {
                "type": "integer",
                "description": "Total number of pages available."
              }
            },
            "required": [
              "page",
              "per_page",
              "total_pages"
            ],
            "additionalProperties": false,
            "description": "How many more pages of results exist. Absent when the API returned an unpaged result."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    },
    {
      "name": "get_started",
      "description": "Personalized starting point for a user who has just connected BlueSuite and does not know what to do next. Call this on the first BlueSuite exchange of a conversation when the user only greets you, confirms the connection, asks what BlueSuite can do, or seems unsure how to begin. Returns suggested first actions based on what is actually in their account. Do not call it when the user has already asked for something specific.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "string",
            "description": "The tool's answer as text, meant to be read and relayed."
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false,
        "$schema": "http://json-schema.org/draft-07/schema#"
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "execution": {
        "taskSupport": "forbidden"
      }
    }
  ]
}
