---
title: "Get parcel permits"
method: GET
path: "/api/v1/parcels/{id}/permits"
tags: ["Parcels"]
---

# Get parcel permits

`GET /api/v1/parcels/{id}/permits`

## Request

- Base URL: `https://propraven.com`
- URL: `https://propraven.com/api/v1/parcels/{id}/permits`
- Auth: HTTP bearer

Retrieve building and construction permits associated with a parcel. ACCOUNT REQUIRED (API key, MCP OAuth token or signed-in session). Each permit carries the people the jurisdiction filed on it: `owner_name`, `applicant_name`, `permit_contacts` (every published phone and e-mail with its role, "unknown" where the publisher states none) and `people_fields_published` (the publisher's own people fields, verbatim). Each served read is recorded in PropRaven's people-data access log. LOOKUP CAP (2026-10-10): a response that carries at least one of these people fields counts as ONE lookup against the account's monthly lookup cap, exactly like an owner card (a paid plan includes it; a response with no people field counts nothing; the record page's own read spends nothing twice). At the cap the people fields are null, `people_fields.code` is `lookup_cap_reached` (on the envelope and on each row) and the permits are still returned; nothing is charged. See `lookups` on GET /api/v1/account/usage. PERMIT EVENTS (#868): a permit whose jurisdiction publishes them carries `events` (its inspections, fees, conditions, plan reviews and other records, newest first, at most 25), `event_count`, `events_truncated` and `event_counts`; the envelope's `permit_events_status` says whether they were read. The events' people fields are gated and counted with the permits'.

## Path parameters

- `id` string, required

## Query parameters

- `shape` 'envelope'

## Response `200`

Permits returned. By default the body is a BARE ARRAY of permit rows, at most 100 (newest issued_date first) — a parcel with more permits is silently cut at 100 on this shape. With `?shape=envelope` the body is `{ data, permit_count, permit_count_basis, truncated, row_cap }` so the cap is reported.

- union
  - Permit[]
    - `permit_number` string, nullable, required
    - `permit_type` string, nullable, required
    - `permit_status` string, nullable, required
    - `description` string, nullable, required
    - `work_class` string, nullable, required
    - `issued_date` string, date, nullable, required
    - `completed_date` string, nullable, required
    - `estimated_cost` number, nullable, required
    - `fee_amount` number, nullable, required
    - `contractor_name` string, nullable, required
    - `contractor_license` string, nullable, required
    - `site_address` string, nullable, required
    - `city` string, nullable, required
    - `type` string
    - `status` 'issued' | 'pending' | 'approved' | 'expired' | 'completed' | 'denied'
    - `contractor` string, nullable
    - `permit_id` string, nullable: The permit's row id (a stable id, not people data).
    - `owner_name` string, nullable: PEOPLE DATA (account required): the property owner as the jurisdiction filed it on the permit.
    - `applicant_name` string, nullable: PEOPLE DATA (account required): the applicant as the jurisdiction filed it on the permit.
    - `permit_contacts` object[]: PEOPLE DATA (account required; absent otherwise): every phone and e-mail the publisher released on this permit, with its role. Phones follow the permit contact vocabulary: role owner / applicant / contractor when the key name, the publisher or a role column states it, else "unknown" (served, never promoted to an owner phone). E-mails take their role from the key name, else "unknown"; a value without the shape local@domain.tld is served with valid=false.
      - `kind` 'phone' | 'email', required
      - `role` 'owner' | 'applicant' | 'contractor' | 'unknown', required
      - `role_basis` 'key_name' | 'publisher' | 'role_field' | 'unstated'
      - `name` string, nullable
      - `e164` string, nullable: Phones: +1XXXXXXXXXX, or null when the value is not a plausible NANP number.
      - `display` string, nullable
      - `ext` string, nullable
      - `valid` boolean: E-mails: true when the value has the shape local@domain.tld.
      - `value` string, required: The value exactly as published.
      - `key` string, required: The publisher's field name.
    - `people_fields_published` object: PEOPLE DATA (account required; absent otherwise): the publisher's own owner / applicant / contact / agent fields on this permit (names, mailing addresses, phones, e-mails), verbatim, keyed by the publisher's field name.
    - `people_fields` object: Present on a row only when its people fields were withheld by the lookup meter (`code: lookup_cap_reached` / `lookup_meter_unavailable`): owner_name, applicant_name, permit_contacts and people_fields_published are then null. { status: withheld, code, reason, note }.
    - `events` PermitEvent[]: The permit's events, newest first, at most 25. Absent when the jurisdiction publishes none (see permit_events_status on the envelope).
      - `event_id` string, required: Stable id: <source key>_<publisher row id>, or <source key>_h_<hash of the record's identity fields> when the publisher has no stable row id.
      - `event_type` 'inspection' | 'fee' | 'condition' | 'review' | 'other', required
      - `event_type_raw` string, nullable: The publisher's own type (inspection type, fee type, review type, task).
      - `raw_kind` string, required: The kind of record the source publishes: inspection, fee, stipulation, plan_review, status_history, task, work_item, device, contractor…
      - `event_date` string, date, nullable, required: The record's date (inspection, creation or status date) inside [1900-01-01, release + 365 d]; null otherwise (the publisher's value stays in raw_attributes).
      - `event_status` string, nullable, required: Result or status as published (Pass, Fail, Approved…).
      - `amount` number, nullable, required: Fee amount (fees and work-item fees).
      - `description` string, nullable, required
      - `source_key` string, required: The collected dataset the record came from.
      - `source_url` string, nullable, required
      - `curated_at` string, date, nullable, required: The collection day.
      - `raw_attributes` object, nullable, required: The publisher's record, whole, minus its people-bearing keys (served in people_fields_published).
      - `people_fields_published` object, nullable, required: PEOPLE DATA (account required): the record's contractor / permittee / applicant names, phones and e-mails verbatim; null when withheld (no access, or the lookup cap). Counted with the permits' people fields as one lookup per response.
    - `event_count` integer: The permit's true event count.
    - `events_truncated` boolean: True when the permit has more events than `events` carries; GET /api/v1/permits/{permit_id}/events lists them.
    - `event_counts` PermitEventCounts
      - `inspection` integer
      - `fee` integer
      - `condition` integer
      - `review` integer
      - `other` integer
  - object
    - `data` Permit[], required
      - `permit_number` string, nullable, required
      - `permit_type` string, nullable, required
      - `permit_status` string, nullable, required
      - `description` string, nullable, required
      - `work_class` string, nullable, required
      - `issued_date` string, date, nullable, required
      - `completed_date` string, nullable, required
      - `estimated_cost` number, nullable, required
      - `fee_amount` number, nullable, required
      - `contractor_name` string, nullable, required
      - `contractor_license` string, nullable, required
      - `site_address` string, nullable, required
      - `city` string, nullable, required
      - `type` string
      - `status` 'issued' | 'pending' | 'approved' | 'expired' | 'completed' | 'denied'
      - `contractor` string, nullable
      - `permit_id` string, nullable: The permit's row id (a stable id, not people data).
      - `owner_name` string, nullable: PEOPLE DATA (account required): the property owner as the jurisdiction filed it on the permit.
      - `applicant_name` string, nullable: PEOPLE DATA (account required): the applicant as the jurisdiction filed it on the permit.
      - `permit_contacts` object[]: PEOPLE DATA (account required; absent otherwise): every phone and e-mail the publisher released on this permit, with its role. Phones follow the permit contact vocabulary: role owner / applicant / contractor when the key name, the publisher or a role column states it, else "unknown" (served, never promoted to an owner phone). E-mails take their role from the key name, else "unknown"; a value without the shape local@domain.tld is served with valid=false.
        - `kind` 'phone' | 'email', required
        - `role` 'owner' | 'applicant' | 'contractor' | 'unknown', required
        - `role_basis` 'key_name' | 'publisher' | 'role_field' | 'unstated'
        - `name` string, nullable
        - `e164` string, nullable: Phones: +1XXXXXXXXXX, or null when the value is not a plausible NANP number.
        - `display` string, nullable
        - `ext` string, nullable
        - `valid` boolean: E-mails: true when the value has the shape local@domain.tld.
        - `value` string, required: The value exactly as published.
        - `key` string, required: The publisher's field name.
      - `people_fields_published` object: PEOPLE DATA (account required; absent otherwise): the publisher's own owner / applicant / contact / agent fields on this permit (names, mailing addresses, phones, e-mails), verbatim, keyed by the publisher's field name.
      - `people_fields` object: Present on a row only when its people fields were withheld by the lookup meter (`code: lookup_cap_reached` / `lookup_meter_unavailable`): owner_name, applicant_name, permit_contacts and people_fields_published are then null. { status: withheld, code, reason, note }.
      - `events` PermitEvent[]: The permit's events, newest first, at most 25. Absent when the jurisdiction publishes none (see permit_events_status on the envelope).
        - `event_id` string, required: Stable id: <source key>_<publisher row id>, or <source key>_h_<hash of the record's identity fields> when the publisher has no stable row id.
        - `event_type` 'inspection' | 'fee' | 'condition' | 'review' | 'other', required
        - `event_type_raw` string, nullable: The publisher's own type (inspection type, fee type, review type, task).
        - `raw_kind` string, required: The kind of record the source publishes: inspection, fee, stipulation, plan_review, status_history, task, work_item, device, contractor…
        - `event_date` string, date, nullable, required: The record's date (inspection, creation or status date) inside [1900-01-01, release + 365 d]; null otherwise (the publisher's value stays in raw_attributes).
        - `event_status` string, nullable, required: Result or status as published (Pass, Fail, Approved…).
        - `amount` number, nullable, required: Fee amount (fees and work-item fees).
        - `description` string, nullable, required
        - `source_key` string, required: The collected dataset the record came from.
        - `source_url` string, nullable, required
        - `curated_at` string, date, nullable, required: The collection day.
        - `raw_attributes` object, nullable, required: The publisher's record, whole, minus its people-bearing keys (served in people_fields_published).
        - `people_fields_published` object, nullable, required: PEOPLE DATA (account required): the record's contractor / permittee / applicant names, phones and e-mails verbatim; null when withheld (no access, or the lookup cap). Counted with the permits' people fields as one lookup per response.
      - `event_count` integer: The permit's true event count.
      - `events_truncated` boolean: True when the permit has more events than `events` carries; GET /api/v1/permits/{permit_id}/events lists them.
      - `event_counts` PermitEventCounts
        - `inspection` integer
        - `fee` integer
        - `condition` integer
        - `review` integer
        - `other` integer
    - `permit_count` integer, required: The parcel's permit count (exact) or the capped window size (a floor) — see permit_count_basis.
    - `permit_count_basis` 'exact' | 'capped', required
    - `truncated` boolean, required: True when the parcel has more permits than `data` carries.
    - `row_cap` integer, required: The row cap `data` is bounded by (100).
    - `permit_contacts_status` 'listed' | 'none_published' | 'unavailable': Whether the listed permits published any phone or e-mail (`listed`), none (`none_published`), or the contact read failed (`unavailable`; names are still served).
    - `people_fields` object: Present only when people fields were withheld: a caller without people-data access (`code: account_required`), or an account at its monthly lookup cap (`code: lookup_cap_reached`, with `upgrade`) or whose lookup meter could not be read (`code: lookup_meter_unavailable`). { status: withheld, code, reason, note }.
    - `permit_events_status` 'listed' | 'none_published' | 'not_loaded' | 'unavailable': Whether the listed permits' events were read: listed / none_published (read), not_loaded / unavailable (not read; the permits are still served).

## Other responses

- `400`: A query or body parameter is invalid. Nothing was read or charged.
- `401`: Missing, malformed or invalid credential.
- `404`: The resource (or the endpoint) does not exist.
- `405`: The endpoint exists but does not support this method. `Allow` lists the methods it does.
- `429`: Rate limit exceeded.
- `500`: Unexpected server error. The body never carries database or driver text.

---

[API](https://skmtc.dev/propraven/apis/propraven-api.md) · [All operations](https://skmtc.dev/propraven/apis/propraven-api/llms.txt) · [OpenAPI document](https://skmtc.dev/propraven/apis/propraven-api/revisions/37f8158c4eda?raw)
