openapi: 3.0.3
info:
  title: Terminal AI GTM Lab x Sauron — Data Source APIs
  version: 1.0.0
  description: |
    ## TL;DR
    Live, no-auth public APIs behind the two Sauron projects. Every endpoint here was called successfully on 2026-09-02,
    all return CORS headers, so **"Try it out" works directly from this page**.

    | Need | Endpoint | Auth |
    |---|---|---|
    | Incident-level crime, City of LA | `LAPD NIBRS Offenses` (Socrata SODA) | none |
    | $5M+ homes by zip | `LA County Parcels` (ArcGIS REST) | none |
    | Permits — City of LA | `LADBS Permits` (SODA) | none |
    | Permits — San Francisco | `DataSF Building Permits` (SODA) | none |
    | Permits — Miami-Dade | `Miami-Dade Building Permits` (ArcGIS REST) | none |
    | Owner name / AVM / sales history | `ATTOM Property API` | API key (30-day trial) |

    **Not covered by any public API:** Beverly Hills PD crime, homeowner email/phone (skip-trace vendor), MLS closings (MLS license or ATTOM).

    ### Query cheat-sheet
    * **Socrata (SODA)** — `$where`, `$select`, `$order`, `$limit`, `$offset`. SoQL syntax, e.g. `$where=date_occ > '2026-08-01' AND area_name = 'West LA'`. Optional `X-App-Token` header raises rate limits.
    * **ArcGIS REST** — `where` (SQL), `outFields`, `resultRecordCount`, `resultOffset`, `returnGeometry`, `returnCountOnly`, `f=json`.

tags:
  - name: Crime — LAPD
    description: LAPD NIBRS Offenses (current, bi-weekly refresh). Locations are hundred-block + lat/lon; **no zip code field**. Covers City of LA only (Pacific Palisades 90272, Brentwood 90049, Bel Air 90077 = area_name "West LA"; Hollywood Hills part of 90046 = "Hollywood").
  - name: Property — LA County Assessor
    description: Parcel-level assessed values, use type, situs address. **No owner name in this dataset.**
  - name: Permits — City of LA (LADBS)
  - name: Permits — San Francisco (DataSF)
  - name: Permits — Miami-Dade
  - name: Property — ATTOM (paid)
    description: Owner name, AVM, sales history. Requires `apikey` header from https://api.developer.attomdata.com/signup.

paths:
  /k7nn-b2ep.json:
    servers:
      - url: https://data.lacity.org/resource
    get:
      tags: [Crime — LAPD]
      summary: LAPD NIBRS Offenses — recent property crimes in West LA
      operationId: lapdNibrsOffenses
      description: |
        Default example returns burglaries / larcenies / motor-vehicle thefts / robberies reported in the last 14 days in the West LA area.
        NIBRS codes: 220 Burglary, 23x Larceny, 240 MV Theft, 120 Robbery, 13A/13B Assault, 290 Vandalism, 200 Arson, 90J Trespass.
      parameters:
        - name: $where
          in: query
          schema:
            type: string
            default: "area_name like 'West LA%' AND crime_against = 'Property' AND date_occ > '2026-08-15T00:00:00'"
        - name: $select
          in: query
          schema:
            type: string
            default: "caseno,date_occ,nibr_code,nibr_description,premis_desc,area_name,rpt_dist_no,hndrdth_loc_chk,hndrdth_lat,hndrdth_lon"
        - name: $order
          in: query
          schema: { type: string, default: "date_occ DESC" }
        - name: $limit
          in: query
          schema: { type: integer, default: 25 }
        - name: $offset
          in: query
          schema: { type: integer }
        - name: X-App-Token
          in: header
          required: false
          schema: { type: string }
      responses:
        "200":
          description: Array of offense records
          content:
            application/json:
              schema:
                type: array
                items: { $ref: "#/components/schemas/LapdOffense" }
              example:
                - caseno: "25163991"
                  date_occ: "2025-09-02T07:42:00.000"
                  nibr_code: "220"
                  nibr_description: "459 - PC - F - Burglary - Residential - 220"
                  premis_desc: "Single Family Dwelling"
                  area_name: "West LA"
                  rpt_dist_no: "0821"
                  hndrdth_loc_chk: "1200 Monaco Dr"
                  hndrdth_lat: "34.0623"
                  hndrdth_lon: "-118.5279"

  /2nrs-mtv8.json:
    servers:
      - url: https://data.lacity.org/resource
    get:
      tags: [Crime — LAPD]
      summary: LAPD legacy crime data 2020–2024 (FROZEN — historical only)
      operationId: lapdLegacyCrime
      description: No longer updated after LAPD's NIBRS migration. Useful for backtesting / baselines only.
      parameters:
        - name: $where
          in: query
          schema:
            type: string
            default: "area_name = 'West LA' AND crm_cd_desc like '%BURGLARY%' AND date_occ > '2024-01-01T00:00:00'"
        - name: $order
          in: query
          schema: { type: string, default: "date_occ DESC" }
        - name: $limit
          in: query
          schema: { type: integer, default: 10 }
      responses:
        "200":
          description: Array of legacy crime records
          content:
            application/json:
              example:
                - dr_no: "240812345"
                  date_occ: "2024-02-10T00:00:00.000"
                  area_name: "West LA"
                  crm_cd_desc: "BURGLARY"
                  premis_desc: "SINGLE FAMILY DWELLING"
                  location: "1100 S  WESTMORELAND                 AV"
                  lat: "34.0508"
                  lon: "-118.2891"

  /LACounty_Cache/LACounty_Parcel/MapServer/0/query:
    servers:
      - url: https://public.gis.lacounty.gov/public/rest/services
    get:
      tags: [Property — LA County Assessor]
      summary: LA County parcels — $5M+ homes in a zip code
      operationId: laCountyParcels
      description: |
        ArcGIS FeatureServer query. Default example: single-family parcels in 90272 with assessed value (land + improvements) over $5M.
        `Roll_HomeOwnersExemp > 0` ⇒ owner-occupied (proxy for person vs. business ownership).
        Max 1000 records per call — paginate with `resultOffset`. Assessed value ≠ market value (Prop 13).
        Target zips: 90210 Beverly Hills, 90077 Bel Air, 90049 Brentwood, 90046 West Hollywood, 90272 Pacific Palisades.
      parameters:
        - name: where
          in: query
          required: true
          schema:
            type: string
            default: "SitusZIP LIKE '90272%' AND (Roll_LandValue+Roll_ImpValue) > 5000000 AND UseType = 'Residential'"
        - name: outFields
          in: query
          schema:
            type: string
            default: "AIN,SitusFullAddress,SitusZIP,UseDescription,Roll_LandValue,Roll_ImpValue,Roll_HomeOwnersExemp,YearBuilt1,SQFTmain1,Bedrooms1,Bathrooms1,CENTER_LAT,CENTER_LON"
        - name: orderByFields
          in: query
          schema: { type: string, default: "Roll_LandValue DESC" }
        - name: resultRecordCount
          in: query
          schema: { type: integer, default: 10, maximum: 1000 }
        - name: resultOffset
          in: query
          schema: { type: integer, default: 0 }
        - name: returnGeometry
          in: query
          schema: { type: boolean, default: false }
        - name: returnCountOnly
          in: query
          schema: { type: boolean, default: false }
        - name: f
          in: query
          required: true
          schema: { type: string, default: json, enum: [json, geojson] }
      responses:
        "200":
          description: ArcGIS feature set
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ArcGisFeatureSet" }
              example:
                displayFieldName: AIN
                features:
                  - attributes:
                      AIN: "4407012003"
                      SitusFullAddress: "1250 MONACO DR LOS ANGELES CA 90272"
                      SitusZIP: "90272"
                      UseDescription: "Single Family Residence"
                      Roll_LandValue: 6252023
                      Roll_ImpValue: 1563005
                      Roll_HomeOwnersExemp: 7000
                      YearBuilt1: 1954
                      SQFTmain1: 4210
                      CENTER_LAT: 34.0623
                      CENTER_LON: -118.5279

  /pi9x-tg5x.json:
    servers:
      - url: https://data.lacity.org/resource
    get:
      tags: [Permits — City of LA (LADBS)]
      summary: LADBS building permits issued 2020–present
      operationId: ladbsPermits
      parameters:
        - name: $where
          in: query
          schema:
            type: string
            default: "zip_code in ('90272','90049','90077','90046') AND issue_date > '2026-08-01T00:00:00' AND valuation::number > 100000"
        - name: $select
          in: query
          schema:
            type: string
            default: "permit_nbr,primary_address,zip_code,apn,permit_type,permit_sub_type,use_desc,issue_date,status_desc,valuation,lat,lon"
        - name: $order
          in: query
          schema: { type: string, default: "issue_date DESC" }
        - name: $limit
          in: query
          schema: { type: integer, default: 25 }
      responses:
        "200":
          description: Array of permits
          content:
            application/json:
              example:
                - permit_nbr: "22016-90000-38688"
                  primary_address: "9229 N VALJEAN AVE"
                  zip_code: "91343"
                  apn: "2676018025"
                  permit_type: "Bldg-Alter/Repair"
                  permit_sub_type: "1 or 2 Family Dwelling"
                  use_desc: "Dwelling - Single Family"
                  issue_date: "2022-12-22T00:00:00.000"
                  status_desc: "Permit Finaled"
                  valuation: "5000"

  /i98e-djp9.json:
    servers:
      - url: https://data.sfgov.org/resource
    get:
      tags: [Permits — San Francisco (DataSF)]
      summary: SF DBI building permits
      operationId: sfPermits
      parameters:
        - name: $where
          in: query
          schema:
            type: string
            default: "filed_date > '2026-08-01T00:00:00' AND estimated_cost::number > 250000"
        - name: $select
          in: query
          schema:
            type: string
            default: "permit_number,permit_type_definition,filed_date,issued_date,status,street_number,street_name,street_suffix,zipcode,description,estimated_cost"
        - name: $order
          in: query
          schema: { type: string, default: "filed_date DESC" }
        - name: $limit
          in: query
          schema: { type: integer, default: 25 }
      responses:
        "200":
          description: Array of permits
          content:
            application/json:
              example:
                - permit_number: "201806293452"
                  permit_type_definition: "additions alterations or repairs"
                  filed_date: "2018-06-29T00:00:00.000"
                  status: "issued"
                  street_number: "930"
                  street_name: "Sutter"
                  street_suffix: "St"
                  zipcode: "94109"
                  estimated_cost: "350000"

  /MD_LandInformation/MapServer/1/query:
    servers:
      - url: https://gisweb.miamidade.gov/arcgis/rest/services
    get:
      tags: [Permits — Miami-Dade]
      summary: Miami-Dade County building permits (last 3 years, weekly refresh)
      operationId: miamiDadePermits
      parameters:
        - name: where
          in: query
          required: true
          schema: { type: string, default: "1=1" }
        - name: outFields
          in: query
          schema: { type: string, default: "ID,PROCNUM,FOLIO,ADDRESS,UNIT,TYPE,CAT1,DESC1,ISCONDO" }
        - name: orderByFields
          in: query
          schema: { type: string, default: "ID DESC" }
        - name: resultRecordCount
          in: query
          schema: { type: integer, default: 10, maximum: 1000 }
        - name: resultOffset
          in: query
          schema: { type: integer, default: 0 }
        - name: returnGeometry
          in: query
          schema: { type: boolean, default: false }
        - name: f
          in: query
          required: true
          schema: { type: string, default: json, enum: [json, geojson] }
      responses:
        "200":
          description: ArcGIS feature set
          content:
            application/json:
              schema: { $ref: "#/components/schemas/ArcGisFeatureSet" }
              example:
                displayFieldName: PROCNUM
                features:
                  - attributes:
                      ID: 2023069958
                      PROCNUM: "M2023069958"
                      FOLIO: "3040100000000"
                      ADDRESS: "1234 NW 12 AVE"
                      TYPE: "BLDG"
                      DESC1: "SINGLE FAMILY RESIDENCE"

  /propertyapi/v1.0.0/property/detailowner:
    servers:
      - url: https://api.gateway.attomdata.com
    get:
      tags: [Property — ATTOM (paid)]
      summary: ATTOM — property detail with owner name (requires API key)
      operationId: attomDetailOwner
      description: Returns owner name(s), mailing address, and property characteristics. Will return 401 without a valid `apikey`. Pair with `/saleshistory/detail` and `/attomavm/detail`.
      security:
        - attomApiKey: []
      parameters:
        - name: address1
          in: query
          required: true
          schema: { type: string, default: "1250 Monaco Dr" }
        - name: address2
          in: query
          required: true
          schema: { type: string, default: "Pacific Palisades, CA 90272" }
        - name: accept
          in: header
          schema: { type: string, default: application/json }
      responses:
        "200":
          description: Property with owner block
          content:
            application/json:
              example:
                status: { code: 0, msg: SuccessWithResult, total: 1 }
                property:
                  - identifier: { attomId: 184196315, apn: "4407-012-003" }
                    address: { oneLine: "1250 MONACO DR, PACIFIC PALISADES, CA 90272" }
                    owner:
                      owner1: { lastName: "DOE", firstNameAndMi: "JANE" }
                      mailingAddressOneLine: "1250 MONACO DR, PACIFIC PALISADES, CA 90272"
                      corporateIndicator: "N"
                      absenteeOwnerStatus: "O"
        "401":
          description: Missing / invalid apikey

components:
  securitySchemes:
    attomApiKey:
      type: apiKey
      in: header
      name: apikey
  schemas:
    LapdOffense:
      type: object
      properties:
        caseno: { type: string }
        date_rptd: { type: string, format: date-time }
        date_occ: { type: string, format: date-time }
        area_name: { type: string }
        rpt_dist_no: { type: string }
        nibr_code: { type: string }
        nibr_description: { type: string }
        crime_against: { type: string, enum: [Property, Person, Society] }
        premis_desc: { type: string }
        status_desc: { type: string }
        hndrdth_loc_chk: { type: string, description: Hundred-block address }
        hndrdth_lat: { type: string }
        hndrdth_lon: { type: string }
    ArcGisFeatureSet:
      type: object
      properties:
        displayFieldName: { type: string }
        fields:
          type: array
          items: { type: object }
        features:
          type: array
          items:
            type: object
            properties:
              attributes: { type: object }
        exceededTransferLimit: { type: boolean }
