{
  "openapi": "3.0.1",
  "info": {
    "title": "Accela Citizen Access & EnerGov Permit Scraper (Any City)",
    "description": "Scrape building permits from US cities and counties on Accela Citizen Access or Tyler EnerGov Citizen Self Service portals: permit type, status, dates, valuation, address, contractor. Normalized JSON, daily new-permit monitor with webhooks. No login, no proxies. $0.003/permit.",
    "version": "0.1",
    "x-build-id": "12IjFvgc4XCuVgy2V"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/owlabee~accela-energov-permit-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-owlabee-accela-energov-permit-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/owlabee~accela-energov-permit-scraper/runs": {
      "post": {
        "operationId": "runs-sync-owlabee-accela-energov-permit-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/owlabee~accela-energov-permit-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-owlabee-accela-energov-permit-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "jurisdictions"
        ],
        "properties": {
          "jurisdictions": {
            "title": "Jurisdictions",
            "minItems": 1,
            "uniqueItems": true,
            "type": "array",
            "description": "Cities and counties to query. Each entry is one Accela Citizen Access (ACA) or Tyler EnerGov Citizen Self Service portal from the verified registry. Groups: \"all-latest\" crawls every supported portal and grows when portals are added; \"all\" keeps the fixed list of the first 31 portals, so a saved input returns the same portals at the same cost; \"-energov\"/\"-accela\" variants of both limit the group to one vendor. Each portal queried is one paid portal-run event; see the README table for engine, date semantics and volume per jurisdiction.",
            "items": {
              "type": "string",
              "enum": [
                "all-latest",
                "all",
                "all-energov-latest",
                "all-energov",
                "all-accela-latest",
                "all-accela",
                "richmond-va",
                "overland-park-ks",
                "southlake-tx",
                "doral-fl",
                "hernando-county-fl",
                "riverside-county-ca",
                "santa-fe-nm",
                "danville-ca",
                "carson-ca",
                "imperial-beach-ca",
                "wilmington-nc",
                "la-vergne-tn",
                "grand-traverse-county-mi",
                "reading-pa",
                "shelton-wa",
                "snohomish-wa",
                "rockland-county-ny",
                "sacramento-ca",
                "tampa-fl",
                "hillsborough-county-fl",
                "oakland-ca",
                "san-mateo-county-ca",
                "stockton-ca",
                "monterey-county-ca",
                "santa-clara-county-ca",
                "mesa-az",
                "omaha-ne",
                "oklahoma-city-ok",
                "fort-worth-tx",
                "denver-co",
                "charlotte-nc",
                "petaluma-ca",
                "okeechobee-county-fl",
                "pembroke-pines-fl",
                "ashland-or",
                "clark-county-nv",
                "pima-county-az",
                "san-antonio-tx",
                "pinellas-county-fl",
                "polk-county-fl",
                "osceola-county-fl",
                "chesterfield-county-va",
                "lincoln-lancaster-county-ne",
                "olmsted-county-mn",
                "butte-county-ca",
                "albany-or"
              ],
              "enumTitles": [
                "All supported jurisdictions, including new ones (46 portals; grows as portals are added)",
                "All first-release jurisdictions (31 portals; fixed list)",
                "All EnerGov portals, including new ones (21)",
                "All first-release EnerGov portals (17; fixed list)",
                "All Accela Citizen Access portals, including new ones (25)",
                "All first-release Accela Citizen Access portals (14; fixed list)",
                "Richmond, VA (EnerGov)",
                "Overland Park, KS (EnerGov)",
                "Southlake, TX (EnerGov)",
                "Doral, FL (EnerGov)",
                "Hernando County, FL (EnerGov)",
                "Riverside County, CA (unincorporated) (EnerGov)",
                "Santa Fe, NM (EnerGov)",
                "Danville, CA (EnerGov)",
                "Carson, CA (EnerGov)",
                "Imperial Beach, CA (EnerGov)",
                "Wilmington, NC (EnerGov)",
                "La Vergne, TN (EnerGov)",
                "Grand Traverse County, MI (EnerGov)",
                "Reading, PA (EnerGov)",
                "Shelton, WA (EnerGov)",
                "Snohomish, WA (EnerGov)",
                "Rockland County, NY (EnerGov)",
                "Sacramento, CA (Accela ACA)",
                "Tampa, FL (Accela ACA)",
                "Hillsborough County, FL (Accela ACA)",
                "Oakland, CA (Accela ACA)",
                "San Mateo County, CA (Accela ACA)",
                "Stockton, CA (Accela ACA)",
                "Monterey County, CA (Accela ACA)",
                "Santa Clara County, CA (Accela ACA)",
                "Mesa, AZ (Accela ACA)",
                "Omaha, NE (Accela ACA)",
                "Oklahoma City, OK (Accela ACA)",
                "Fort Worth, TX (Accela ACA)",
                "Denver, CO (Accela ACA)",
                "Charlotte, NC (land development) (Accela ACA)",
                "Petaluma, CA (EnerGov)",
                "Okeechobee County, FL (EnerGov)",
                "Pembroke Pines, FL (EnerGov)",
                "Ashland, OR (EnerGov)",
                "Clark County, NV (Accela ACA)",
                "Pima County, AZ (Accela ACA)",
                "San Antonio, TX (Accela ACA)",
                "Pinellas County, FL (Accela ACA)",
                "Polk County, FL (Accela ACA)",
                "Osceola County, FL (Accela ACA)",
                "Chesterfield County, VA (Accela ACA)",
                "Lincoln / Lancaster County, NE (Accela ACA)",
                "Olmsted County, MN (incl. Rochester) (Accela ACA)",
                "Butte County, CA (Accela ACA)",
                "Albany, OR (Accela ACA)"
              ]
            },
            "default": [
              "overland-park-ks",
              "southlake-tx"
            ]
          },
          "issuedWithinDays": {
            "title": "Issued within (days)",
            "minimum": 1,
            "maximum": 365,
            "type": "integer",
            "description": "Only permits whose portal date falls in the last N days (1–365). EnerGov portals filter on the issued date; Accela Citizen Access general search filters on the record (application) date, so on ACA this is \"applied within\". Applied server-side on every portal, so narrow windows are fast and cheap.",
            "default": 30
          },
          "permitTypes": {
            "title": "Permit type keywords (optional)",
            "type": "array",
            "description": "Keep only permits whose type or work class contains one of these words, case-insensitive (for example \"electrical\", \"roof\", \"solar\", \"demolition\", \"residential\"). Each portal uses its own type vocabulary, so prefer generic words. Applied client-side after the date filter.",
            "items": {
              "type": "string"
            }
          },
          "keyword": {
            "title": "Work description keyword (optional)",
            "type": "string",
            "description": "Keep only permits whose description (or type) contains this text, case-insensitive (for example \"solar\", \"re-roof\", \"kitchen\", \"ADU\"). EnerGov applies it server-side on the description; Accela applies it client-side."
          },
          "minEstimatedCost": {
            "title": "Minimum valuation (USD, optional)",
            "minimum": 0,
            "type": "integer",
            "description": "Drop permits whose declared job value / valuation is below this amount. Valuation is only known when includeDetails is on; permits with no published value are kept (estimatedCost is null)."
          },
          "maxResultsPerJurisdiction": {
            "title": "Max permits per jurisdiction",
            "minimum": 1,
            "maximum": 20000,
            "type": "integer",
            "description": "Upper bound on permit records saved per jurisdiction per run (newest first). Use it together with the run's maximum cost and the time budget to control spend.",
            "default": 500
          },
          "maxSecondsPerJurisdiction": {
            "title": "Time budget per jurisdiction (seconds)",
            "minimum": 60,
            "maximum": 3600,
            "type": "integer",
            "description": "Wall-clock limit for one portal (bootstrap, paging and details). When it runs out, the permits collected so far are saved and the portal is marked truncated in the SUMMARY; a portal that produced nothing yet returns a TIME_BUDGET error item. Independently of this limit, a portal that delivers no results page or detail record for 60 s (stalling, timing out or blocking) is abandoned the same way. Raise it for year-long crawls of large Accela cities with details.",
            "default": 900
          },
          "includeDetails": {
            "title": "Fetch permit details",
            "type": "boolean",
            "description": "Open every permit's detail record or page to add valuation (estimatedCost), contractor and license, owner, applicant and parcel number. One extra request per permit, charged as a permit-detail-fetched event; roughly 1 s per permit per portal. Off for the daily Store test.",
            "default": false
          },
          "onlyNewSinceLastRun": {
            "title": "Only new permits since last run",
            "type": "boolean",
            "description": "Monitor mode for schedules: remember the permit ids already seen per jurisdiction (up to 50,000 each) in the state store and emit only permits not seen before, flagged isNew: true. The first run is a baseline and emits (and charges for) everything in the window. Details are fetched only for new permits.",
            "default": false
          },
          "stateStoreName": {
            "title": "State store name",
            "type": "string",
            "description": "Named key-value store that holds the seen-permit sets for monitor mode. Use a different name per schedule if two schedules query the same jurisdiction with different filters.",
            "default": "accela-energov-permit-scraper-state"
          },
          "includeRaw": {
            "title": "Include raw source record",
            "type": "boolean",
            "description": "Attach the untouched portal row (and detail, when fetched) as \"raw\" on every permit, so you can read portal-specific fields the normalized schema does not carry. Roughly doubles dataset size.",
            "default": false
          },
          "accelaAppId": {
            "title": "Accela developer app id (optional)",
            "type": "string",
            "description": "Optional app id from a free Accela developer-portal app. When set, Accela jurisdictions are queried through the official Construct API in its anonymous mode (JSON, includes addresses, parcels, professionals, owners) instead of the Citizen Access page. Agencies that do not allow anonymous API access return an error item; remove the id to use the page engine again. Stored encrypted and never logged."
          },
          "webhookUrl": {
            "title": "Webhook URL (optional)",
            "pattern": "^https?://.+",
            "type": "string",
            "description": "If set, the Actor POSTs a JSON run summary plus the emitted permits (max 500; only the new ones in monitor mode) to this URL when it finishes. Failures are logged, never fatal."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}