{
  "openapi": "3.1.0",
  "info": {
    "title": "FieldServiceScout Agent API",
    "version": "1.0.0",
    "summary": "Independent field-service software comparison data, for agents.",
    "description": "FieldServiceScout is an independent comparison platform for field-service management (FSM) software used by trade contractors — HVAC, plumbing, electrical, roofing, landscaping, and pest control. This read-only API exposes the same catalog, scoring engine, and true-cost model that the website renders.\n\n**When to use this API:** when a user needs field-service software recommended, priced, or compared; when you need a platform's real capability matrix rather than its marketing copy; or when you need an all-in cost that includes card-processing fees, which routinely exceed the licence fee and invert a sticker-price ranking.\n\n**When not to use it:** it does not sell software, provision trials, transact, or return vendor quotes. Every price is modeled from published list prices (as of July 2026) and is indicative only.\n\n**Authentication:** none. Every endpoint is public, read-only, and rate limited per client IP. No key to provision, no account to create.\n\n**Attribution:** figures are citable to the `meta.source_url` on every response. The scoring rubric is published in full at the `meta.methodology_url`.",
    "contact": {
      "name": "FieldServiceScout editorial",
      "email": "corrections@fieldservicescout.com",
      "url": "https://www.fieldservicescout.com/contact"
    },
    "license": {
      "name": "Data available for citation with attribution",
      "url": "https://www.fieldservicescout.com/docs#terms"
    },
    "termsOfService": "https://www.fieldservicescout.com/docs#terms"
  },
  "servers": [
    {
      "url": "https://www.fieldservicescout.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "FieldServiceScout",
      "description": "Field-service software catalog, ranking, and true-cost operations."
    }
  ],
  "externalDocs": {
    "description": "Human-readable API documentation, with runnable examples.",
    "url": "https://www.fieldservicescout.com/docs"
  },
  "paths": {
    "/api/agent/v1/vendors": {
      "get": {
        "operationId": "listFieldServiceVendors",
        "summary": "List the field-service software platforms in the catalog",
        "description": "Returns every field-service management (FSM) platform FieldServiceScout scores, with segment, trade coverage, card-processing rate, and an indicative all-in monthly cost for a sample 8-technician shop. Filterable by trade, segment, and required capabilities.\n\n**When to use:** Use when the user asks what field-service/FSM software exists for a trade, or you need the valid vendor slugs before calling another operation.",
        "tags": [
          "FieldServiceScout"
        ],
        "parameters": [
          {
            "name": "trade",
            "in": "query",
            "required": false,
            "description": "Restrict to platforms that actually sell into this trade. Omit to include every platform in the catalog.",
            "schema": {
              "type": "string",
              "enum": [
                "hvac",
                "plumbing",
                "electrical",
                "roofing",
                "landscaping",
                "pest-control"
              ]
            },
            "example": "hvac"
          },
          {
            "name": "segment",
            "in": "query",
            "required": false,
            "description": "The shop's job mix. `residential` for homeowner service calls, `commercial` for contract/B2B work, `mixed` for both.",
            "schema": {
              "type": "string",
              "enum": [
                "residential",
                "commercial",
                "mixed"
              ]
            },
            "example": "residential"
          },
          {
            "name": "must_have",
            "in": "query",
            "required": false,
            "description": "Comma-separated capabilities a platform must support to appear in the list. Platforms lacking any of them are omitted.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "scheduling",
                  "dispatch",
                  "mobile",
                  "invoicing",
                  "payments",
                  "quickbooks",
                  "memberships",
                  "commercial",
                  "inventory",
                  "reporting",
                  "marketing",
                  "portal",
                  "gps"
                ]
              },
              "maxItems": 13
            },
            "style": "form",
            "explode": false,
            "example": "quickbooks"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of platforms to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "List the field-service software platforms in the catalog",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorListResponse"
                }
              }
            }
          },
          "400": {
            "description": "A parameter was missing, malformed, or out of range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the window in the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server-side failure; the request itself was valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/v1/vendors/{slug}": {
      "get": {
        "operationId": "getFieldServiceVendor",
        "summary": "Get one platform's full profile",
        "description": "Returns a single platform's capability matrix (every feature marked included, add-on, or unsupported), its published plan structure, the pricing page and month the figures were verified against, and an indicative cost for a sample shop.\n\n**When to use:** Use when the user names a specific platform and wants its features, plans, or pricing — or when you need to check whether one platform supports a particular capability.",
        "tags": [
          "FieldServiceScout"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The platform's identifier, as returned by `listFieldServiceVendors`.",
            "schema": {
              "type": "string",
              "enum": [
                "jobber",
                "housecall-pro",
                "servicetitan",
                "workiz",
                "service-fusion",
                "fieldedge",
                "servicem8",
                "fieldpulse",
                "gorilladesk",
                "kickserv",
                "buildops",
                "razorsync",
                "acculynx",
                "jobnimbus",
                "aspire",
                "lmn",
                "fieldroutes",
                "pestpac",
                "briostack",
                "servicetrade"
              ]
            },
            "example": "jobber"
          }
        ],
        "responses": {
          "200": {
            "description": "Get one platform's full profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "A parameter was missing, malformed, or out of range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "No resource exists at that path or identifier.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the window in the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server-side failure; the request itself was valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/v1/match": {
      "get": {
        "operationId": "matchFieldServiceSoftware",
        "summary": "Rank platforms against one shop's requirements",
        "description": "Runs the published scoring engine over the catalog and returns a ranked shortlist. Dealbreakers (`must_have`) are applied first as hard filters; surviving platforms get a 0–100 composite weighting feature fit (55%), budget fit (23%), and segment fit (22%). Every result carries its score breakdown, the needs it covers, the needs it misses, and a full cost estimate, so the ranking can be audited rather than taken on faith.\n\n**When to use:** Use when the user describes their shop — crew size, trade, budget, must-have capabilities — and wants a recommendation. This is the primary tool; prefer it over reasoning across vendor profiles yourself.",
        "tags": [
          "FieldServiceScout"
        ],
        "parameters": [
          {
            "name": "seats",
            "in": "query",
            "required": false,
            "description": "Number of technicians/users the shop needs licensed. Drives plan selection and per-seat pricing.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100000,
              "default": 8
            },
            "example": 8
          },
          {
            "name": "monthly_card_volume",
            "in": "query",
            "required": false,
            "description": "Monthly credit-card volume in USD. Multiplied by each vendor's processing rate to produce the true all-in cost — the figure that separates platforms far more than licence price does.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000000,
              "default": 42000
            },
            "example": 42000
          },
          {
            "name": "segment",
            "in": "query",
            "required": false,
            "description": "The shop's job mix. `residential` for homeowner service calls, `commercial` for contract/B2B work, `mixed` for both.",
            "schema": {
              "type": "string",
              "enum": [
                "residential",
                "commercial",
                "mixed"
              ],
              "default": "mixed"
            },
            "example": "residential"
          },
          {
            "name": "trade",
            "in": "query",
            "required": false,
            "description": "Restrict to platforms that actually sell into this trade. Omit to include every platform in the catalog.",
            "schema": {
              "type": "string",
              "enum": [
                "hvac",
                "plumbing",
                "electrical",
                "roofing",
                "landscaping",
                "pest-control"
              ]
            },
            "example": "hvac"
          },
          {
            "name": "needs",
            "in": "query",
            "required": false,
            "description": "Comma-separated capabilities the shop wants, scored as 55% of the composite. One of: `scheduling` (Scheduling & calendar), `dispatch` (Dispatch board), `mobile` (Tech mobile app), `invoicing` (Invoicing & estimates), `payments` (Built-in card payments), `quickbooks` (QuickBooks sync), `memberships` (Service agreements / plans), `commercial` (Commercial & contract jobs), `inventory` (Inventory tracking), `reporting` (Reporting & dashboards), `marketing` (Marketing automation), `portal` (Customer portal), `gps` (GPS fleet tracking).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "scheduling",
                  "dispatch",
                  "mobile",
                  "invoicing",
                  "payments",
                  "quickbooks",
                  "memberships",
                  "commercial",
                  "inventory",
                  "reporting",
                  "marketing",
                  "portal",
                  "gps"
                ]
              },
              "maxItems": 13
            },
            "style": "form",
            "explode": false,
            "example": "scheduling,dispatch,quickbooks"
          },
          {
            "name": "must_have",
            "in": "query",
            "required": false,
            "description": "Comma-separated dealbreakers. Any platform lacking one of these is removed from the ranking entirely rather than scored down, and is returned under `ruled_out` with the reason.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "scheduling",
                  "dispatch",
                  "mobile",
                  "invoicing",
                  "payments",
                  "quickbooks",
                  "memberships",
                  "commercial",
                  "inventory",
                  "reporting",
                  "marketing",
                  "portal",
                  "gps"
                ]
              },
              "maxItems": 13
            },
            "style": "form",
            "explode": false,
            "example": "quickbooks"
          },
          {
            "name": "budget_per_tech",
            "in": "query",
            "required": false,
            "description": "Target all-in spend per technician per month in USD. Platforms over it are penalised proportionally, not removed. Omit if the user has no figure in mind — a blank budget scores neutrally rather than flattering cheap tools.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 100000
            },
            "example": 120
          },
          {
            "name": "android_required",
            "in": "query",
            "required": false,
            "description": "Set true when the crew carries Android phones. Removes any platform whose field app is iPhone-only.",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "example": true
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many ranked platforms to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 5
            },
            "example": 5
          }
        ],
        "responses": {
          "200": {
            "description": "Rank platforms against one shop's requirements",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchResponse"
                }
              }
            }
          },
          "400": {
            "description": "A parameter was missing, malformed, or out of range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the window in the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server-side failure; the request itself was valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/v1/cost-estimate": {
      "get": {
        "operationId": "estimateFieldServiceSoftwareCost",
        "summary": "Model the true all-in cost of one or more platforms",
        "description": "Returns modeled monthly, annual, and three-year cost for the requested platforms at a given crew size and card volume, split into software licence cost and payment-processing cost. Processing fees routinely exceed the licence fee, so a comparison on sticker price alone is usually wrong; this operation is what makes the real ranking visible.\n\n**When to use:** Use when the user asks what a platform will actually cost, or wants two or more platforms' costs compared at their own crew size and card volume.",
        "tags": [
          "FieldServiceScout"
        ],
        "parameters": [
          {
            "name": "vendors",
            "in": "query",
            "required": false,
            "description": "Comma-separated platform slugs. Omit to model every platform in the catalog.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "jobber",
                  "housecall-pro",
                  "servicetitan",
                  "workiz",
                  "service-fusion",
                  "fieldedge",
                  "servicem8",
                  "fieldpulse",
                  "gorilladesk",
                  "kickserv",
                  "buildops",
                  "razorsync",
                  "acculynx",
                  "jobnimbus",
                  "aspire",
                  "lmn",
                  "fieldroutes",
                  "pestpac",
                  "briostack",
                  "servicetrade"
                ]
              },
              "maxItems": 50
            },
            "style": "form",
            "explode": false,
            "example": "jobber,housecall-pro"
          },
          {
            "name": "seats",
            "in": "query",
            "required": false,
            "description": "Number of technicians/users the shop needs licensed. Drives plan selection and per-seat pricing.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100000,
              "default": 8
            },
            "example": 8
          },
          {
            "name": "monthly_card_volume",
            "in": "query",
            "required": false,
            "description": "Monthly credit-card volume in USD. Multiplied by each vendor's processing rate to produce the true all-in cost — the figure that separates platforms far more than licence price does.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000000,
              "default": 42000
            },
            "example": 42000
          },
          {
            "name": "plan",
            "in": "query",
            "required": false,
            "description": "Force a specific named plan (only meaningful with a single vendor). Defaults to the cheapest plan with verified pricing at the requested seat count.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Model the true all-in cost of one or more platforms",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CostEstimateResponse"
                }
              }
            }
          },
          "400": {
            "description": "A parameter was missing, malformed, or out of range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the window in the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server-side failure; the request itself was valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/v1/compare": {
      "get": {
        "operationId": "compareFieldServiceVendors",
        "summary": "Compare two platforms feature-by-feature and on true cost",
        "description": "Returns a head-to-head of exactly two platforms: every capability with each side's support level, the capabilities where they differ, and both true-cost estimates at the requested crew size and card volume.\n\n**When to use:** Use when the user names two platforms and asks which is better, or how they differ. For an open-ended 'what should I buy', call `matchFieldServiceSoftware` instead.",
        "tags": [
          "FieldServiceScout"
        ],
        "parameters": [
          {
            "name": "vendors",
            "in": "query",
            "required": true,
            "description": "Exactly two comma-separated platform slugs, e.g. `jobber,housecall-pro`.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "jobber",
                  "housecall-pro",
                  "servicetitan",
                  "workiz",
                  "service-fusion",
                  "fieldedge",
                  "servicem8",
                  "fieldpulse",
                  "gorilladesk",
                  "kickserv",
                  "buildops",
                  "razorsync",
                  "acculynx",
                  "jobnimbus",
                  "aspire",
                  "lmn",
                  "fieldroutes",
                  "pestpac",
                  "briostack",
                  "servicetrade"
                ]
              },
              "minItems": 2,
              "maxItems": 2
            },
            "style": "form",
            "explode": false,
            "example": "jobber,housecall-pro"
          },
          {
            "name": "seats",
            "in": "query",
            "required": false,
            "description": "Number of technicians/users the shop needs licensed. Drives plan selection and per-seat pricing.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100000,
              "default": 8
            },
            "example": 8
          },
          {
            "name": "monthly_card_volume",
            "in": "query",
            "required": false,
            "description": "Monthly credit-card volume in USD. Multiplied by each vendor's processing rate to produce the true all-in cost — the figure that separates platforms far more than licence price does.",
            "schema": {
              "type": "number",
              "minimum": 0,
              "maximum": 1000000000,
              "default": 42000
            },
            "example": 42000
          }
        ],
        "responses": {
          "200": {
            "description": "Compare two platforms feature-by-feature and on true cost",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompareResponse"
                }
              }
            }
          },
          "400": {
            "description": "A parameter was missing, malformed, or out of range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the window in the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server-side failure; the request itself was valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/v1/tools": {
      "get": {
        "operationId": "listAgentTools",
        "summary": "List these tools as function-calling definitions, or as OpenAPI",
        "description": "Returns every operation in this API as an LLM function-calling definition (name, description, JSON Schema parameters). Pass `format=openapi` for the equivalent OpenAPI 3.1 document, which is also served at /openapi.json.\n\n**When to use:** Use once at the start of a session to discover what FieldServiceScout can answer, or to load these tools into a function-calling runtime automatically.",
        "tags": [
          "FieldServiceScout"
        ],
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "`tools` (default) for function-calling definitions; `openapi` for the OpenAPI 3.1 document.",
            "schema": {
              "type": "string",
              "enum": [
                "tools",
                "openapi"
              ],
              "default": "tools"
            },
            "example": "openapi"
          }
        ],
        "responses": {
          "200": {
            "description": "List these tools as function-calling definitions, or as OpenAPI",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolsResponse"
                }
              }
            }
          },
          "400": {
            "description": "A parameter was missing, malformed, or out of range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the window in the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server-side failure; the request itself was valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ResponseMeta": {
        "type": "object",
        "description": "Provenance for the figures in this response, so a caller can cite them.",
        "properties": {
          "source": {
            "type": "string",
            "description": "Always \"FieldServiceScout\"."
          },
          "source_url": {
            "type": "string",
            "description": "Canonical site URL.",
            "format": "uri"
          },
          "methodology_url": {
            "type": "string",
            "description": "The published scoring methodology.",
            "format": "uri"
          },
          "documentation_url": {
            "type": "string",
            "description": "This API's documentation.",
            "format": "uri"
          },
          "pricing_as_of": {
            "type": "string",
            "description": "The month the plan prices behind every cost figure were verified."
          },
          "content_reviewed": {
            "type": "string",
            "description": "ISO date the underlying catalog was last editorially reviewed.",
            "format": "date"
          }
        },
        "required": [
          "source",
          "source_url",
          "pricing_as_of"
        ]
      },
      "FeatureSupport": {
        "type": "object",
        "description": "One capability and how fully a platform supports it.",
        "properties": {
          "key": {
            "type": "string",
            "description": "Capability identifier.",
            "enum": [
              "scheduling",
              "dispatch",
              "mobile",
              "invoicing",
              "payments",
              "quickbooks",
              "memberships",
              "commercial",
              "inventory",
              "reporting",
              "marketing",
              "portal",
              "gps"
            ]
          },
          "label": {
            "type": "string",
            "description": "Human-readable capability name."
          },
          "support": {
            "type": "string",
            "description": "`included` ships in the plan, `addon` costs extra or needs a higher tier, `none` is unsupported.",
            "enum": [
              "included",
              "addon",
              "none"
            ]
          }
        },
        "required": [
          "key",
          "label",
          "support"
        ]
      },
      "Plan": {
        "type": "object",
        "description": "One published pricing plan, as listed on the vendor's own pricing page.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Plan name as the vendor markets it."
          },
          "base_usd": {
            "type": "number",
            "description": "Monthly list base price in USD, or null when the plan is quote-only.",
            "nullable": true
          },
          "included_seats": {
            "type": "integer",
            "description": "Seats bundled into the base price, or null when none are.",
            "nullable": true
          },
          "per_user_usd": {
            "type": "number",
            "description": "Monthly USD per seat beyond the included seats, or null.",
            "nullable": true
          },
          "custom_quote": {
            "type": "boolean",
            "description": "True when the vendor quotes this plan rather than publishing a price."
          },
          "price_unverified": {
            "type": "boolean",
            "description": "True when no published price has been verified for this plan yet."
          },
          "monthly_usd_at_8_techs": {
            "type": "number",
            "description": "Modeled monthly software cost for an 8-technician shop."
          }
        },
        "required": [
          "name",
          "custom_quote",
          "price_unverified",
          "monthly_usd_at_8_techs"
        ]
      },
      "VendorSummary": {
        "type": "object",
        "description": "A field-service management platform, summarised.",
        "properties": {
          "slug": {
            "type": "string",
            "description": "Stable identifier used everywhere else in this API.",
            "enum": [
              "jobber",
              "housecall-pro",
              "servicetitan",
              "workiz",
              "service-fusion",
              "fieldedge",
              "servicem8",
              "fieldpulse",
              "gorilladesk",
              "kickserv",
              "buildops",
              "razorsync",
              "acculynx",
              "jobnimbus",
              "aspire",
              "lmn",
              "fieldroutes",
              "pestpac",
              "briostack",
              "servicetrade"
            ]
          },
          "name": {
            "type": "string",
            "description": "Platform name."
          },
          "url": {
            "type": "string",
            "description": "FieldServiceScout's profile page for this platform.",
            "format": "uri"
          },
          "website": {
            "type": "string",
            "description": "The vendor's own website.",
            "format": "uri",
            "nullable": true
          },
          "segment": {
            "type": "string",
            "description": "The job mix this platform is built for.",
            "enum": [
              "residential",
              "commercial",
              "mixed"
            ]
          },
          "best_for": {
            "type": "string",
            "description": "One line on the shop this platform is the right answer for."
          },
          "year_founded": {
            "type": "integer",
            "description": "Year the vendor was founded."
          },
          "trades": {
            "type": "array",
            "nullable": true,
            "description": "Trade slugs this platform sells into. Null means a generalist platform eligible for every trade.",
            "items": {
              "type": "string",
              "enum": [
                "hvac",
                "plumbing",
                "electrical",
                "roofing",
                "landscaping",
                "pest-control"
              ]
            }
          },
          "payment_processing_rate_pct": {
            "type": "number",
            "description": "Card-processing rate in percent. Applied to card volume in every cost estimate — usually the largest cost difference between platforms."
          },
          "monetized": {
            "type": "boolean",
            "description": "True when FieldServiceScout earns a commission on this platform. Disclosed on every response; the scoring engine never reads it."
          },
          "estimated_monthly_usd_at_8_techs": {
            "type": "number",
            "description": "Indicative all-in monthly cost (software + card processing) for a sample 8-technician shop doing $42,000/month on cards."
          }
        },
        "required": [
          "slug",
          "name",
          "url",
          "segment",
          "best_for",
          "monetized"
        ]
      },
      "VendorDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/VendorSummary"
          },
          {
            "type": "object",
            "description": "Full platform profile.",
            "properties": {
              "summary": {
                "type": "string",
                "description": "Editorial summary of the platform's strengths and limits."
              },
              "android_app": {
                "type": "boolean",
                "description": "True when the field app ships on Android as well as iOS."
              },
              "features": {
                "type": "array",
                "description": "Every scored capability with this platform's support level.",
                "items": {
                  "$ref": "#/components/schemas/FeatureSupport"
                }
              },
              "plans": {
                "type": "array",
                "description": "Published plans, priced at an 8-technician shop.",
                "items": {
                  "$ref": "#/components/schemas/Plan"
                }
              },
              "pricing_source": {
                "type": "object",
                "description": "Where and when these plan prices were verified. Null when the vendor publishes no list prices.",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "The vendor's public pricing page.",
                    "format": "uri"
                  },
                  "as_of": {
                    "type": "string",
                    "description": "Month the figures were last checked against that page."
                  },
                  "note": {
                    "type": "string",
                    "description": "Any caveat about the figures."
                  }
                },
                "required": [
                  "url",
                  "as_of"
                ]
              }
            },
            "required": [
              "summary",
              "features",
              "plans"
            ]
          }
        ],
        "description": "A platform profile including its capability matrix and plan structure."
      },
      "CostEstimate": {
        "type": "object",
        "description": "Modeled true cost for one platform at a given crew size and card volume.",
        "properties": {
          "vendor_slug": {
            "type": "string",
            "description": "Platform identifier."
          },
          "vendor_name": {
            "type": "string",
            "description": "Platform name."
          },
          "plan_name": {
            "type": "string",
            "description": "The plan this estimate prices."
          },
          "custom_quote": {
            "type": "boolean",
            "description": "True when the plan is quote-only, making the figure a placeholder."
          },
          "software_usd_per_month": {
            "type": "number",
            "description": "Monthly licence cost in USD."
          },
          "payment_processing_usd_per_month": {
            "type": "number",
            "description": "Monthly card-processing cost in USD (card volume x the platform's rate)."
          },
          "total_usd_per_month": {
            "type": "number",
            "description": "Software plus processing, per month."
          },
          "usd_per_tech_per_month": {
            "type": "number",
            "description": "Total monthly cost divided by seats."
          },
          "total_usd_per_year": {
            "type": "number",
            "description": "Total monthly cost x 12."
          },
          "total_usd_three_year": {
            "type": "number",
            "description": "Total monthly cost x 36."
          }
        },
        "required": [
          "vendor_slug",
          "vendor_name",
          "plan_name",
          "software_usd_per_month",
          "payment_processing_usd_per_month",
          "total_usd_per_month"
        ]
      },
      "Match": {
        "type": "object",
        "description": "One ranked platform, with the arithmetic behind its position.",
        "properties": {
          "rank": {
            "type": "integer",
            "description": "1-based position in the ranking."
          },
          "vendor": {
            "$ref": "#/components/schemas/VendorSummary"
          },
          "score": {
            "type": "number",
            "description": "Composite 0–100 score.",
            "minimum": 0,
            "maximum": 100
          },
          "rationale": {
            "type": "string",
            "description": "Plain-language justification generated from the same inputs as the score."
          },
          "score_breakdown": {
            "type": "object",
            "description": "The three weighted components of the composite, each 0–1 before weighting.",
            "properties": {
              "feature_fit": {
                "type": "number",
                "description": "Fit against the stated needs. Weighted 0.55."
              },
              "budget_fit": {
                "type": "number",
                "description": "Fit against the stated per-tech budget. Weighted 0.23."
              },
              "segment_fit": {
                "type": "number",
                "description": "Residential/commercial fit. Weighted 0.22."
              },
              "weights": {
                "type": "object",
                "description": "The published weights actually applied.",
                "properties": {
                  "feature": {
                    "type": "number",
                    "description": "Feature-fit weight."
                  },
                  "budget": {
                    "type": "number",
                    "description": "Budget-fit weight."
                  },
                  "segment": {
                    "type": "number",
                    "description": "Segment-fit weight."
                  }
                },
                "required": [
                  "feature",
                  "budget",
                  "segment"
                ]
              }
            },
            "required": [
              "feature_fit",
              "budget_fit",
              "segment_fit",
              "weights"
            ]
          },
          "over_budget": {
            "type": "boolean",
            "description": "True when the estimate exceeds the stated per-tech budget."
          },
          "covers": {
            "type": "array",
            "description": "Stated needs this platform supports outright.",
            "items": {
              "type": "string"
            }
          },
          "gaps": {
            "type": "array",
            "description": "Stated needs this platform does not support at all.",
            "items": {
              "type": "string"
            }
          },
          "cost_estimate": {
            "$ref": "#/components/schemas/CostEstimate"
          }
        },
        "required": [
          "rank",
          "vendor",
          "score",
          "rationale",
          "score_breakdown",
          "cost_estimate"
        ]
      },
      "RuledOut": {
        "type": "object",
        "description": "A platform removed by a dealbreaker rather than ranked.",
        "properties": {
          "vendor_slug": {
            "type": "string",
            "description": "Platform identifier."
          },
          "vendor_name": {
            "type": "string",
            "description": "Platform name."
          },
          "reason": {
            "type": "string",
            "description": "Which dealbreaker removed it."
          }
        },
        "required": [
          "vendor_slug",
          "vendor_name",
          "reason"
        ]
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Every failure from this API returns this shape — never an HTML error page.",
        "properties": {
          "error": {
            "type": "string",
            "description": "The error code, duplicated at the top level for convenience.",
            "enum": [
              "invalid_request",
              "not_found",
              "method_not_allowed",
              "rate_limited",
              "cross_origin",
              "internal_error"
            ]
          },
          "error_detail": {
            "type": "object",
            "description": "Structured detail: what failed, and what to do about it.",
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable code. Branch on this.",
                "enum": [
                  "invalid_request",
                  "not_found",
                  "method_not_allowed",
                  "rate_limited",
                  "cross_origin",
                  "internal_error"
                ]
              },
              "message": {
                "type": "string",
                "description": "One-sentence human-readable explanation."
              },
              "hint": {
                "type": "string",
                "description": "The concrete next action that resolves this error."
              },
              "documentation_url": {
                "type": "string",
                "description": "Where to read more.",
                "format": "uri"
              },
              "errors": {
                "type": "array",
                "description": "Field-level detail, present on `invalid_request`.",
                "items": {
                  "type": "object",
                  "description": "One invalid field.",
                  "properties": {
                    "field": {
                      "type": "string",
                      "description": "Parameter name."
                    },
                    "message": {
                      "type": "string",
                      "description": "Why it was rejected."
                    }
                  },
                  "required": [
                    "field",
                    "message"
                  ]
                }
              }
            },
            "required": [
              "code",
              "message",
              "hint",
              "documentation_url"
            ]
          }
        },
        "required": [
          "error",
          "error_detail"
        ]
      },
      "VendorListResponse": {
        "type": "object",
        "description": "A filtered list of platforms.",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          },
          "count": {
            "type": "integer",
            "description": "Number of items returned."
          },
          "results": {
            "type": "array",
            "description": "The result set.",
            "items": {
              "$ref": "#/components/schemas/VendorSummary"
            }
          },
          "filters_applied": {
            "type": "object",
            "description": "Echo of the filters this response was built with.",
            "properties": {
              "trade": {
                "type": "string",
                "description": "Trade filter, or null.",
                "nullable": true
              },
              "segment": {
                "type": "string",
                "description": "Segment filter, or null.",
                "nullable": true
              },
              "must_have": {
                "type": "array",
                "description": "Capability filters applied.",
                "items": {
                  "type": "string",
                  "enum": [
                    "scheduling",
                    "dispatch",
                    "mobile",
                    "invoicing",
                    "payments",
                    "quickbooks",
                    "memberships",
                    "commercial",
                    "inventory",
                    "reporting",
                    "marketing",
                    "portal",
                    "gps"
                  ]
                }
              }
            },
            "required": []
          }
        },
        "required": [
          "meta",
          "count",
          "results"
        ]
      },
      "VendorDetailResponse": {
        "type": "object",
        "description": "One platform's full profile.",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          },
          "vendor": {
            "$ref": "#/components/schemas/VendorDetail"
          },
          "pricing_disclaimer": {
            "type": "string",
            "description": "Why every cost figure here is indicative, not a quote."
          }
        },
        "required": [
          "meta",
          "vendor"
        ]
      },
      "MatchResponse": {
        "type": "object",
        "description": "A ranked shortlist for one shop's requirements.",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          },
          "profile": {
            "type": "object",
            "description": "The requirements this ranking was computed from — echoed so a caller can confirm how its input was parsed.",
            "properties": {
              "seats": {
                "type": "integer",
                "description": "Technicians licensed."
              },
              "monthly_card_volume": {
                "type": "number",
                "description": "Monthly card volume in USD."
              },
              "segment": {
                "type": "string",
                "description": "Job mix."
              },
              "trade": {
                "type": "string",
                "description": "Trade filter, or null.",
                "nullable": true
              },
              "needs": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Scored needs."
              },
              "must_have": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Dealbreakers."
              },
              "budget_per_tech": {
                "type": "number",
                "description": "Stated per-tech budget, or null.",
                "nullable": true
              },
              "android_required": {
                "type": "boolean",
                "description": "Whether Android support was required."
              }
            },
            "required": [
              "seats",
              "monthly_card_volume",
              "segment"
            ]
          },
          "count": {
            "type": "integer",
            "description": "Number of ranked platforms returned."
          },
          "results": {
            "type": "array",
            "description": "Ranked platforms, best first.",
            "items": {
              "$ref": "#/components/schemas/Match"
            }
          },
          "ruled_out": {
            "type": "array",
            "description": "Platforms removed by a dealbreaker, with the reason for each.",
            "items": {
              "$ref": "#/components/schemas/RuledOut"
            }
          },
          "methodology": {
            "type": "string",
            "description": "One-line statement of the rubric used."
          },
          "pricing_disclaimer": {
            "type": "string",
            "description": "Why every cost figure here is indicative, not a quote."
          }
        },
        "required": [
          "meta",
          "profile",
          "count",
          "results"
        ]
      },
      "CostEstimateResponse": {
        "type": "object",
        "description": "Modeled costs for the requested platforms.",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          },
          "assumptions": {
            "type": "object",
            "description": "The inputs every figure below was computed from.",
            "properties": {
              "seats": {
                "type": "integer",
                "description": "Technicians licensed."
              },
              "monthly_card_volume": {
                "type": "number",
                "description": "Monthly card volume in USD."
              },
              "plan": {
                "type": "string",
                "description": "Forced plan name, or null for the cheapest verified plan.",
                "nullable": true
              }
            },
            "required": [
              "seats",
              "monthly_card_volume"
            ]
          },
          "count": {
            "type": "integer",
            "description": "Number of estimates returned."
          },
          "results": {
            "type": "array",
            "description": "One estimate per platform, cheapest total first.",
            "items": {
              "$ref": "#/components/schemas/CostEstimate"
            }
          },
          "pricing_disclaimer": {
            "type": "string",
            "description": "Why every cost figure here is indicative, not a quote."
          }
        },
        "required": [
          "meta",
          "assumptions",
          "count",
          "results"
        ]
      },
      "CompareResponse": {
        "type": "object",
        "description": "A head-to-head of exactly two platforms.",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          },
          "vendors": {
            "type": "array",
            "description": "The two platforms, in the order requested.",
            "items": {
              "$ref": "#/components/schemas/VendorDetail"
            }
          },
          "differences": {
            "type": "array",
            "description": "Only the capabilities where the two platforms differ.",
            "items": {
              "type": "object",
              "description": "One capability where support differs.",
              "properties": {
                "key": {
                  "type": "string",
                  "description": "Capability identifier.",
                  "enum": [
                    "scheduling",
                    "dispatch",
                    "mobile",
                    "invoicing",
                    "payments",
                    "quickbooks",
                    "memberships",
                    "commercial",
                    "inventory",
                    "reporting",
                    "marketing",
                    "portal",
                    "gps"
                  ]
                },
                "label": {
                  "type": "string",
                  "description": "Human-readable capability name."
                },
                "support": {
                  "type": "object",
                  "description": "Support level keyed by platform slug.",
                  "additionalProperties": {
                    "type": "string",
                    "enum": [
                      "included",
                      "addon",
                      "none"
                    ]
                  }
                }
              },
              "required": [
                "key",
                "label",
                "support"
              ]
            }
          },
          "cost_estimates": {
            "type": "array",
            "description": "True-cost estimate for each platform at the requested inputs.",
            "items": {
              "$ref": "#/components/schemas/CostEstimate"
            }
          },
          "comparison_url": {
            "type": "string",
            "description": "The human-readable comparison page, when one is published.",
            "format": "uri",
            "nullable": true
          },
          "pricing_disclaimer": {
            "type": "string",
            "description": "Why every cost figure here is indicative, not a quote."
          }
        },
        "required": [
          "meta",
          "vendors",
          "differences",
          "cost_estimates"
        ]
      },
      "ToolsResponse": {
        "type": "object",
        "description": "Every operation in this API as an LLM function-calling definition.",
        "properties": {
          "meta": {
            "$ref": "#/components/schemas/ResponseMeta"
          },
          "openapi_url": {
            "type": "string",
            "description": "The equivalent OpenAPI 3.1 document.",
            "format": "uri"
          },
          "when_to_use": {
            "type": "array",
            "description": "The jobs this API is the right tool for.",
            "items": {
              "type": "string"
            }
          },
          "count": {
            "type": "integer",
            "description": "Number of tools."
          },
          "tools": {
            "type": "array",
            "description": "Function-calling definitions, each with its HTTP invocation.",
            "items": {
              "type": "object",
              "description": "One tool.",
              "properties": {
                "type": {
                  "type": "string",
                  "description": "Always \"function\"."
                },
                "function": {
                  "type": "object",
                  "description": "The function-calling definition.",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "Unique function name; matches the OpenAPI operationId."
                    },
                    "description": {
                      "type": "string",
                      "description": "What it does and when to reach for it."
                    },
                    "parameters": {
                      "type": "object",
                      "description": "JSON Schema for the arguments."
                    }
                  },
                  "required": [
                    "name",
                    "description",
                    "parameters"
                  ]
                },
                "invocation": {
                  "type": "object",
                  "description": "How to call it over HTTP.",
                  "properties": {
                    "method": {
                      "type": "string",
                      "description": "Always GET."
                    },
                    "url": {
                      "type": "string",
                      "description": "Absolute endpoint URL.",
                      "format": "uri"
                    },
                    "path_template": {
                      "type": "string",
                      "description": "Path template, with `{}` placeholders."
                    },
                    "example_url": {
                      "type": "string",
                      "description": "A working example request.",
                      "format": "uri"
                    }
                  },
                  "required": [
                    "method",
                    "url"
                  ]
                },
                "when_to_use": {
                  "type": "string",
                  "description": "The decision this tool is for."
                }
              },
              "required": [
                "type",
                "function",
                "invocation"
              ]
            }
          }
        },
        "required": [
          "meta",
          "count",
          "tools"
        ]
      }
    }
  },
  "security": []
}