Skip to main content
Plumb Intelligence

Developers

PlumbIntel API

REST + JSON access to Arizona building permits, the AZ ROC contractor roster, multi-permit project clusters, property characteristics, and contractor-relationship signals — the same intelligence the app runs on. Pipe it into your CRM, tools, or model. 1M+ permits across 25 Arizona jurisdictions, most refreshed daily.

$499/mo
the full API + the dashboard, included
  • • All 12 read endpoints, every dataset
  • • Up to 10,000 requests/day
  • • Up to 5 API keys + the Plumb dashboard
  • • Daily-fresh permits, contractors, parcels

✨ Start free — a 14-day trial with real data, no card required.

Quickstart

  1. Create a key under Settings → API access (org admins on an API-enabled plan). It’s shown once — store it securely. Pick Live or Test — test keys (pk_test_…) read the same data but are capped at 1,000 req/day for dev & CI.
  2. Send it as a bearer token on every request.
  3. Read the data envelope back. That’s it.

Request

curl "https://plumbintel.com/api/v1/permits?jurisdiction=phoenix&freshness=hot&limit=2" \
  -H "Authorization: Bearer pk_live_your_key_here"

JavaScript

const res = await fetch(
  "https://plumbintel.com/api/v1/permits?jurisdiction=phoenix&freshness=hot&limit=2",
  { headers: { Authorization: "Bearer pk_live_your_key_here" } },
);
const { data } = await res.json();
console.log(data.permits);

Response (trimmed)

{
  "data": {
    "permits": [
      {
        "id": "fffcf083-c6cf-4b31-a1c9-f4bd32aff87d",
        "permitNumber": "BLD-2026-03608",
        "permitType": "Residential - New Single Family",
        "workClass": "New",
        "status": "Issued",
        "lifecycleStage": "issued",
        "leadFreshness": "hot",
        "leadScore": 0.82,
        "issueDate": "2026-06-22",
        "valuationTotal": 412000,
        "valuationImputed": null,
        "valuationIsImputed": false,
        "address": "1429 E PALM ST",
        "city": "PHOENIX", "state": "AZ", "zip": "85006",
        "apn": "11942003",
        "jurisdiction": "phoenix",
        "contractor": {
          "license": "ROC123456",
          "businessName": "DESERT SKY BUILDERS LLC",
          "classification": "B-01",
          "status": "Active",
          "hasActiveDisciplinary": false
        }
      }
    ],
    "hasMore": true
  },
  "count": 1
}

The permit object

The core resource. Other endpoints reuse these fields; the contractor, parcel, and project objects are documented in the full API reference.

FieldTypeDescription
idstring (uuid)Stable permit identifier — safe to store and join on.
permitNumberstringThe jurisdiction’s own permit number.
permitTypestringPermit type as filed by the jurisdiction.
workClassstring | nullWork classification (e.g. New, Alteration, Reroof).
statusstringRaw status text from the source portal.
lifecycleStageenumNormalized stage: applied · issued · in_progress · finaled.
leadFreshnessenumRecency band for prospecting: hot · warm · cold · dead.
leadScorenumberLead-quality score from 0 to 1.
issueDatestring (date) | nullISO issue date. Null for applied-only permits (some feeds omit it).
valuationTotalnumber | nullDeclared construction value as filed. 0 or null when the source didn’t report one.
valuationImputednumber | nullEstimated value when none was filed — labeled, never blended into valuationTotal.
valuationIsImputedbooleanTrue when valuationImputed is the value to use.
address / city / state / zipstring | nullParsed site address components.
apnstring | nullNormalized Maricopa County parcel number.
jurisdictionstringSource jurisdiction slug (e.g. phoenix, mesa).
contractorobject | nullContractor of record when resolved — license, businessName, classification, status, hasActiveDisciplinary.

Conventions & rate limits

  • Successful responses use the envelope { data, count?, notes? }.
  • List endpoints paginate with limit (max 200) + offset, and return hasMore.
  • Every response carries X-RateLimit-Limit, -Remaining, -Reset (seconds to UTC midnight), and an X-Request-Id you can quote in support.
  • Over your daily cap (10,000 req/day) — or a short per-minute burst — returns 429 with Retry-After.
  • Server-to-server only — keys are secrets; don’t embed them in browser or mobile clients.

Errors

Every error returns the same shape with a stable code you can switch on (message text may change):

{
  "error": {
    "code": "invalid_api_key",
    "message": "The provided API key is invalid or has been revoked."
  },
  "request_id": "8f1c2e4a-7b3d-4a1e-9c2f-5d6e7a8b9c0d"
}
StatuscodeMeaning
400invalid_requestA query, path, or body parameter is malformed (see error.details).
401unauthorized · invalid_api_keyMissing, malformed, or revoked API key.
403api_access_not_enabledThe organization has no active API entitlement.
404not_foundNo resource for that id, license, or APN.
429rate_limitedDaily or per-minute cap reached — back off per the Retry-After header.

Endpoint reference

Permits

GET/api/v1/permits

List permits

Filtered, paginated permit feed (~928K rows, daily-refreshed).

Query parameters
  • zipSingle ZIP code
  • jurisdictionphoenix | mesa | scottsdale | tempe | gilbert | peoria
  • workClassCase-insensitive contains match on work class
  • lifecycleapplied | issued | in_progress | finaled | void | unknown
  • freshnesshot | warm | cold | dead
  • valuationMinMinimum total valuation
  • valuationMaxMaximum total valuation
  • issuedSinceIssued on/after (YYYY-MM-DD)
  • issuedBeforeIssued on/before (YYYY-MM-DD)
  • limitPage size (max 200)
  • offsetResult offset
GET/api/v1/permits/{id}

Get a permit

Single permit by id, enriched with the parcel owner / property block.

Contractors

GET/api/v1/contractors

Search contractors

AZ ROC roster (~64.6K) with the disciplinary / unlicensed-violator overlay.

Query parameters
  • qBusiness-name contains (case-insensitive)
  • classificationExact ROC class code (e.g. 'B-01', 'CR-39')
  • statusExact status (e.g. 'Active')
  • zipBusiness ZIP
  • cityBusiness city (exact)
  • hasDisciplinary'true' for only contractors with active disciplinary
  • limitPage size (max 200)
  • offsetResult offset
GET/api/v1/contractors/{license}

Get a contractor

Single contractor by ROC license, with the nightly activity rollup.

GET/api/v1/contractors/{license}/relationships

Contractor relationship graph

Contractors who co-occur with this one at the same parcel within a time window.

Query parameters
  • windowMonthsLookback months (max 60)
  • coOccurrenceDays± days at same parcel (max 180)
  • minFrequencyMin shared projects to surface
  • limitMax related contractors (max 100)
GET/api/v1/contractors/{license}/purchasing-profile

Inferred material-spend profile

Estimated annualized material spend per category from permit valuations + work-class mix.

Property & parcels

GET/api/v1/parcels

Search property parcels

Maricopa County property records (~1.75M): owner, assessed value, type, year built, land use. Maricopa-only.

Query parameters
  • zipProperty ZIP
  • propertyTypeExact (e.g. 'SINGLE FAMILY', 'COMMERCIAL', 'VACANT')
  • yearBuiltMinBuilt on/after
  • yearBuiltMaxBuilt on/before
  • assessedMinMinimum assessed value
  • assessedMaxMaximum assessed value
  • landUseLand-use description contains
  • limitPage size (max 200)
  • offsetResult offset
GET/api/v1/parcels/{apn}

Get a property

Single parcel by APN (any format), with the most recent permits at that property.

Leads

GET/api/v1/leads/hot

Top-ranked lead feed

Permits ranked by lead score, defaulted to fresh (hot/warm) — a ready-to-work outreach queue.

Query parameters
  • zipSingle ZIP
  • jurisdictionphoenix | mesa | scottsdale | tempe | gilbert | peoria
  • workClassCase-insensitive contains
  • freshnessComma-separated subset of hot,warm,cold,dead (default 'hot,warm')
  • minScoreMinimum lead score 0..1
  • valuationMinMinimum total valuation
  • limitPage size (max 200)
  • offsetResult offset

Projects

GET/api/v1/projects

List project clusters

Multi-permit projects (one parcel + address, 2-25 chained permits over 365d).

Query parameters
  • zipSingle ZIP
  • activeOnly'true' (default) = a permit in the last 90d
  • minValuationMinimum total project valuation
  • limitPage size (max 200)
  • offsetResult offset

Relationships

GET/api/v1/relationships/gaps

GCs missing a recurring sub

General contractors with no recurring subcontractor in a target trade (a pitch list).

Query parameters
  • zipFilter by the GC's modal ZIP
  • workClassTarget trade (contains)
  • gapWorkClassTrade to evaluate the gap in (defaults to workClass)
  • minPermits12moMin GC permits in 365d
  • maxRegularSubsA gap = no sub appears on more than this many permits
  • limitPage size (max 200)
  • offsetResult offset

Exports

GET/api/v1/exports/direct-mail

Direct-mail CSV export

Owner-mailing-formatted CSV (one row per property/owner). Returns text/csv.

Query parameters
  • zipsComma-separated ZIPs
  • workClassesComma-separated work classes
  • valuationMinMin valuation
  • valuationMaxMax valuation
  • sinceDaysTrailing window in days (max 365)
  • freshnessComma-separated freshness (default 'hot,warm')
  • limitMax rows (max 1000)

Versioning & changes

  • The API is versioned in the path — /api/v1 (current version 1.0.0).
  • We add fields and endpoints without notice — parse defensively and ignore unknown fields. We won’t remove or repurpose an existing v1 field.
  • Breaking changes ship under a new version (/api/v2); deprecations are announced here and via Deprecation / Sunset response headers with advance notice.

Changelog

  • 2026-06-25 — Standard error envelope ({ error: { code, message }, request_id }) + X-Request-Id on every response; offset pagination on the lead, project, and relationship-gap feeds.
  • 2026-06-24 — Public v1 launch: permits, contractors, parcels, leads, projects, relationships, exports.

API use is subject to our Terms of Service — note in particular the redistribution restrictions (Section 7): API data is for use inside your own organization and may not be redistributed or resold.