---
title: "Search Contractors"
method: GET
path: "/contractors/search"
tags: ["Contractors", "Contractors"]
---

# Search Contractors

`GET /contractors/search`

Returns contractors doing work within the given location area filtered by type of work. Contractors must meet all specified parameters, with multiple parameters treated as AND queries. Use contractor_classification_derived to filter by derived classifications (ALL specified values required). The permit_q parameter uses full-text search with English stemming (e.g., 'installing' matches 'install'). Multi-word queries use AND semantics (e.g., 'solar panel' finds permits mentioning both words). **NOTE:** Contractors are ordered by the start date of the most recent permit on which they worked.

## Query parameters

- `cursor` string, nullable — Cursor for pagination
- `size` integer
- `include_count` boolean — When true and on the first page (no cursor), include total_count in the response. The count is exact up to 10,000; above that, relation is 'gte'.
- `include_tallies` boolean — Include tag and status tallies in response. Tallies are the only aggregate fields scoped to the search filters (permit_count, avg_job_value and total_job_value are lifetime totals), so they are the way to count a contractor's permits within the searched area and date range. Set to false to omit tally computation for faster response times when tallies are not needed.
- `permit_from` string, date, required — Return permits that started on or after the specified date.This includes all permits with the earliest date (file, issue, or start date) that falls on or after this date. Date format: `YYYY-MM-DD`
- `permit_to` string, date, required — Return permits that started on or before the specified date.This includes all permits with the latest date (file, issue, or end date) that falls on or before this date. Date format: `YYYY-MM-DD`
- `permit_q` string, nullable — Substring to search for in permit description (case-insensitive). Matches anywhere in the text, including partial words.
- `permit_status` string[], nullable — Filter by one or more statuses: final, in_review, inactive, active.
- `permit_min_approval_duration` integer, nullable — Filter by the minimum permit approval duration in days.
- `permit_min_construction_duration` integer, nullable — Filter by the minimum project construction duration in days.
- `permit_min_inspection_pr` integer, nullable — Filter by the minimum inspection pass rate.
- `permit_min_job_value` integer, nullable — Filter by the minimum job value, in cents (e.g. 5000000 = $50,000).
- `permit_min_fees` integer, nullable — Filter by minimum permit fees, in cents (e.g. 5000000 = $50,000).
- `permit_tags` string[], nullable — Filter by one or more tags. Use '-' prefix to exclude tags. Example: ?permit_tags=solar&permit_tags=-roofing (has solar, not roofing).
- `geo_id` string, required — Filter results by geographic area. Accepts: - US state code (e.g. `CA`) - ZIP code (e.g. `90210` or `90210-1234`) - Shovels geolocation ID for an address, city, county, or jurisdiction (e.g. `a4xysKbZwqg`) Resolve addresses and places to geolocation IDs via: - [Search Addresses](/api-reference/addresses/search-addresses) - [Search Cities](/api-reference/cities/search-cities) - [Search Counties](/api-reference/counties/search-counties) - [Search Jurisdictions](/api-reference/jurisdictions/search-jurisdictions) Free-form text such as `"123 Main St"` is not accepted.
- `property_type` string[], nullable — Filter by property type: residential, commercial, industrial, agricultural, vacant land, exempt, miscellaneous, office, recreational. Repeat the key to match any of several types (e.g. `?property_type=residential&property_type=commercial`).
- `property_min_market_value` integer, nullable — Minimum assessed market value of the property, in cents (e.g. 5000000 = $50,000).
- `property_min_building_area` integer, nullable — Minimum total building area in sq ft.
- `property_min_lot_size` integer, nullable — Minimum size of the property lot in sq ft.
- `property_min_story_count` integer, nullable — Minimum number of property stories.
- `property_min_unit_count` integer, nullable — Minimum number of property units
- `contractor_classification_derived` string[], nullable — Filter by derived contractor classifications. Use '-' prefix to exclude. Example: ?classification_derived=electrical&classification_derived=-hvac. Returns results containing ALL specified classifications. Possible values: concrete_and_paving, demolition_and_excavation, electrical, fencing_and_glazing, framing_and_carpentry, general_building_contractor, general_engineering_contractor, hvac, landscaping_and_outdoor_work, other, plumbing, roofing, specialty_trades.
- `contractor_name` string, nullable — Filter by contractor's name or business name (partial match supported). Must be at least 3 characters — shorter patterns cannot use the trigram index and would force a sequential scan.
- `contractor_website` string, nullable — Filter by contractor's website. Don't include the http(s):// prefix.
- `contractor_min_total_job_value` integer, nullable — Minimum lifetime job value of the contractor, in cents (e.g. 5000000 = $50,000).
- `contractor_min_total_permits_count` integer, nullable — Minimum lifetime permits count.
- `contractor_min_inspection_pr` integer, nullable — Minimum lifetime inspection pass rate. The value must be an integer between 0 and 100, inclusive.
- `contractor_license` string, nullable — Filter by the contractor's license

## Response `200`

A list of contractors.

- PaginatedContractorsResponse — Schema for paginated contractors details response.
  - `items` ContractorsRead[], required — The list of items returned in the response following given criteria.
    - `id` string, required — The contractor ID.
    - `license` string, nullable — The contractor license number.
    - `name` string, nullable — The contractor name.
    - `business_name` string, nullable — The contractor business name.
    - `business_type` string, nullable — The type of business: JointVenture, Corporation, Partnership, Limited Liability, Sole Owner.
    - `classification` string, nullable — The contractor's classification/certification.
    - `classification_derived` string[], nullable — Array of derived contractor classifications.
    - `license_issue_date` string, date, nullable — The license issue date.
    - `license_exp_date` string, date, nullable — The license expiration date.
    - `license_inact_date` string, date, nullable — Date when the contractor's license became inactive.
    - `license_act_date` string, date, nullable — Date when the contractor's license became active.
    - `primary_phone` string, nullable — The contractor's primary phone number.
    - `primary_email` string, nullable — The contractor's primary email.
    - `phone` string, nullable — The contractor's phone number(s).
    - `email` string, nullable — The contractor's email(s).
    - `website` string, nullable — The contractor's website).
    - `dba` string, nullable — Doing Business As name for the contractor.
    - `sic` string, nullable — Standard Industrial Classification (SIC) code of the contractor.
    - `naics` string, nullable — North American Industry Classification System (NAICS) code of the contractor.
    - `linkedin_url` string, nullable — LinkedIn URL of the contractor.
    - `revenue` string, nullable — Annual revenue of the contractor's business.
    - `employee_count` string, nullable — Number of employees working for the contractor.
    - `primary_industry` string, nullable — Primary industry in which the contractor operates.
    - `review_count` integer, nullable — Number of reviews the contractor has received.
    - `rating` number, nullable — Rating of the contractor based on reviews.
    - `status_tally` object, nullable — Permit counts by status (active, final, unknown, inactive, in_review). On /contractors/search: filtered by geo and date range parameters. On /contractors (get by ID): unfiltered lifetime counts.
    - `tag_tally` object, nullable — Permit counts by tag. Each permit is counted once under every tag it has — a permit tagged both 'solar' and 'electrical' adds 1 to each. On /contractors/search: filtered by geo and date range parameters. On /contractors (get by ID): unfiltered lifetime counts, so the values can add up to more than permit_count.
    - `permit_count` integer, nullable — Contractor lifetime total permit count across all locations and dates. Not filtered by search parameters.
    - `avg_job_value` integer, nullable — The average job value of all permits in cents (integer value representing dollars × 100).
    - `total_job_value` integer, nullable — The total job value of all permits in cents (integer value representing dollars × 100).
    - `avg_construction_duration` integer, nullable — The average construction duration in days.
    - `avg_inspection_pass_rate` integer, nullable — The average inspection pass rate as a percentage (0-100).
    - `first_seen_date` string, date, nullable — Date when the contractor was first seen in the system.
    - `address` AddressesEmbedded, required — Schema for embedded address object with location data to be used as a nested JSON object.
      - `street_no` string, nullable — The number of the street of the address.
      - `street` string, nullable — The name of the street of the address.
      - `city` string, nullable — The city of the address.
      - `county` string, nullable — The county of the address.
      - `zip_code` string, nullable — The ZIP code of the address.
      - `zip_code_ext` string, nullable — The extension of the ZIP code of the address.
      - `state` string, nullable — The state of the address.
      - `jurisdiction` string, nullable — The jurisdiction the address belongs to.
      - `address_id` string, nullable — The address identifier.
      - `latlng` number[], nullable — The latitude and longitude of the address.
  - `size` integer, required — The number of items returned in the response.
  - `next_cursor` string, nullable, required — The cursor for retrieving the next page of results.
  - `total_count` TotalCount — Capped result count with Elasticsearch-style {value, relation} shape. When the exact count is known and within the cap, relation is "eq" and value is that exact count. When the count exceeds the cap, relation is "gte" and value is the cap the count was probed against, meaning "the actual count is at least value". The cap is COUNT_CAP for every wire-facing endpoint; internal guard paths probe against their own cap, so value carries whatever cap produced it.
    - `value` integer, required — The count value; capped at the probe's cap (10,000 on the wire).
    - `relation` 'eq' | 'gte', required — "eq" means value is the exact count. "gte" means the actual count is at least value (the cap).

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/shovels/apis/the-shovels-api-v2.md) · [All operations](https://skmtc.net/shovels/apis/the-shovels-api-v2/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/shovels/the-shovels-api-v2/versions/d3f0e1f3afa8/schema)
