Build your own permit-lead tracker with AI
Copy one prompt into Claude Code, Codex, Cursor or any AI coding assistant, and it will walk you through building a small tracker for one city's open-data permit feed: last week's permits, the contractor on each, and flags for new, busy and expiring. It is free and you own the code. We use the City of Austin feed as the example because it is public, needs no login and is well documented.
Jump to the promptSee what our finished file looks like (CSV)
What you will have at the end
- A Python script that pulls every permit a city issued last week from its official API, pages through all of it, and backs off when the city rate-limits you
- Clean contractor names, so "ACME ROOFING LLC" and "Acme Roofing, L.L.C." count as one business
- Three flags: new (no permits in that city in the prior 12 months), busy (3 or more this week) and expiring soon (home permits that expire in the next 30 days)
- A Monday CSV with a source link on every row and a short run report
- A run that stops with a clear error when the city renames a column, instead of handing you an empty file
How it works
- Paste the prompt into your AI assistant in an empty folder.
- Work one milestone at a time. Each milestone ends with an acceptance check the AI has to run and show you, such as matching its row count against the city's own count.
- Schedule it for Monday morning on your own computer.
The prompt
Free to copy and change. It uses only the city's official API: no web scraping, no logins, no captchas.
You are helping me build a small permit-lead tracker for ONE city. Work in milestones. After each milestone, run the acceptance check, show me the output, and stop until I say "next". DATA SOURCE - City of Austin, TX "Issued Construction Permits" on the city's open-data portal (Socrata). - Dataset page: https://data.austintexas.gov/d/3syk-w9eu - API endpoint (JSON, no login): https://data.austintexas.gov/resource/3syk-w9eu.json - It uses SoQL query parameters: $select, $where, $order, $limit, $offset. - Columns I care about: permit_number, issue_date, permit_type_desc, permit_class_mapped, work_class, description, status_current, expiresdate, total_job_valuation, permit_location, original_zip, contractor_company_name, contractor_trade, link. - Before you write any parsing code, fetch 3 rows and print the real column names. If a column above is missing, tell me. Do not guess a replacement. STACK - Python 3, standard library plus "requests". One file: tracker.py. Output goes to ./out/. - No database. Keep a local copy of the last 13 months of permits in ./out/history.csv. MILESTONE 1: pull one week - Pull every permit with issue_date from last Monday 00:00 to last Friday 23:59 (city time). - Page through results with $limit=1000 and $offset until a page comes back short. - Wait at least 250 ms between requests. On HTTP 429 or 5xx, back off (4 s, 16 s, 36 s...) and retry, up to 6 tries, then stop with a clear error. - Optional: read a free Socrata app token from the environment variable SOCRATA_APP_TOKEN and send it as the X-App-Token header. Never print it. - Save ./out/week.csv. - Acceptance check: print the row count. Then run a second query with $select=count(*) and the same $where, and confirm the two numbers match. If they do not match, stop and tell me. MILESTONE 2: clean the contractor names - Uppercase, turn "&" into "AND", strip punctuation, squeeze spaces. - Build a company_key by also dropping THE and legal suffixes (LLC, INC, CORP, CO, LTD, LP, LLP, PLLC). - Keep only rows where the contractor looks like a business (has a suffix or a trade word such as ELECTRIC, PLUMBING, ROOFING, CONSTRUCTION, HOMES). Rows that look like a homeowner or a person stay in the file but get business=false. - Acceptance check: print the 20 most common company_key values with their raw spellings, so I can eyeball bad merges. MILESTONE 3: flags - new_contractor = this company_key has zero permits in this city in the 12 months before the week. This needs ./out/history.csv, so first back-fill 13 months (same paging and backoff rules). - busy_contractor = 3 or more permits this week (make the 3 a setting). - expiring_soon = expiresdate falls in the next 30 days and status_current is not Final, Expired or Withdrawn. Print the distinct status_current values first and let me confirm the list. - Acceptance check: pick 3 contractors flagged new and show me the history query that proves they had no permits before. MILESTONE 4: the Monday file - Write ./out/permits-YYYY-MM-DD.csv with one row per permit, the three flags, and a source_url (use the row's link if present, else the dataset page) and a pulled_at timestamp. - Missing values stay blank. Never write 0 for a value the city did not publish. Job value is blank on many rows, and blank is not zero. - Add a header block in ./out/run-report.txt: rows pulled, rows by status, how many rows have no job value, how many have no contractor name. - Acceptance check: open the CSV and show me 5 rows with every column. MILESTONE 5: fail loudly - If the API returns an error that mentions a missing column, or returns something that is not a JSON list, stop with an error that names the column or shows the response. Do not write an empty file and call it a quiet week. - If this week's row count is under 30% of the 8-week average, write a warning at the top of run-report.txt. - Acceptance check: change one column name in the code to a fake one, run it, and show me that it fails with a clear message. Then change it back. MILESTONE 6: run it every week - Show me how to schedule it for Monday 6 AM on my machine (cron on Mac/Linux, Task Scheduler on Windows). - Acceptance check: print the exact schedule line and the command it runs. RULES - Use only the official city API. No scraping of web pages, no logins, no captchas. - Do not add phone numbers, emails or homeowner names to the output, even if a column has them. - If anything about the data surprises you, stop and ask me instead of guessing.
What it can't do (honest limits)
- One city only. Each city publishes permits differently: different column names, different date fields, different ways of naming the contractor. The prompt fits Austin. Pointing it at a second city means redoing milestones 1 to 3 for that city's columns.
- Cities change their feeds. Columns get renamed, datasets move, and APIs slow down or rate-limit. Milestone 5 makes it fail loudly, but someone still has to notice the error and fix the code that week.
- Some cities don't publish what you want. Chicago's building-permit feed has no permit expiration status, so "expiring soon" can't be built from it. Austin's feed leaves the job value blank on many rows.
- Name cleaning is never perfect. Typos and DBA names will split one contractor into two, or merge two into one. Check the top-20 list from milestone 2 every so often.
- No property facts. Year built, assessed value, code cases, flood zone and census-tract figures come from separate county, Census and FEMA sources, each with its own matching problems. This prompt doesn't cover them.
- It runs on your computer. If your laptop is asleep on Monday morning, there is no file.
Build it or rent it?
| Build it with this prompt | Our weekly file | |
|---|---|---|
| Cost | Free, plus your time | $150 per month or $490 per year, one metro (pricing) |
| Cities | One, and you adapt it for each new one | Your pick of Austin, Chicago, Cincinnati, New Orleans or Mesa |
| When a city changes its feed | You fix it | We fix it |
| Property facts on each row | Not included | Austin, Chicago and Cincinnati |
| Expiring and expired home permits | If your city publishes permit status | Austin, Cincinnati, New Orleans and Mesa |
| Missing values | Up to you (the prompt says leave them blank) | Left blank, never filled with zero |
| Delivery | Your computer, if it is awake | A shared Google Drive folder every Monday |
Want it kept running for you?
Want 5 cities kept running, flagged and delivered every Monday? That's the weekly file. We keep the permit feeds for Austin, Chicago, Cincinnati, New Orleans and Mesa working, plus the county, Census and FEMA sources behind the property facts. Each plan covers one metro you choose, with one CSV and Excel file every Monday.
Free sample (25 Austin rows, CSV)Order monthly by emailOrder yearly by email
Prefer to pay per row and run it yourself? Contractor Permit Signals on Apify covers the same 5 cities, and we keep it working.
Questions
Is the prompt really free?
Yes. Copy it, change it, use it for your business. No sign-up.
Which AI assistant should I use?
Any assistant that can create files and run Python on your computer. The prompt is plain text and doesn't depend on one product.
Can I point it at a different city?
Yes, if that city publishes permits through an open-data API. Swap in the dataset address and redo milestones 1 to 3 for its column names. Check the city's data license before you use the data commercially.
Why are you giving this away?
The code is the easy part. The ongoing work is keeping several city feeds working every week as they change, and that is what the weekly file pays for.