Any Pakistani taxpayer, verified in a single call
FBR's IRIS portal shows a taxpayer's active-filer status — behind what looks like a captcha and a browser-only interface. This project turned that manual, one-lookup-at-a-time process into a clean programmatic call, by reading FBR's own frontend closely enough to realize the lock was never really locked.
Arham Mirkar
DataLayer — Enterprise Data Infrastructure
Verification that only works one human at a time
Lending apps, HR teams, and anyone running KYC needs to confirm a person's tax status with FBR. The data is public — but it's served through a portal that expects a human: type an ID, solve a captcha, read the result off the screen, repeat.
That's fine for one check. It falls apart the moment you need to verify a list of a few hundred borrowers, or wire verification into an onboarding flow. The question wasn't whether the data could be automated — it was whether the captcha was a real barrier or just a costume.
Five moves from portal to plain API
This one was less about code and more about looking carefully. The whole solution is small; the value was in the detective work that made it possible.
Capture
Network exportRecorded a full Chrome network export of a real verification on the IRIS site, then wrote a small script to trim gigabytes of traffic down to the handful of FBR calls that actually mattered.
Locate
Read the frontendFound the endpoint and an application Bearer token hardcoded in IRIS's own Angular bundle — base_verification_url and authorization_key_verifcation (FBR's own spelling) — sitting in plain sight in the minified JavaScript.
Defeat the captcha
The key insightThe captcha looked like the blocker. Reading the bundle revealed it is generated and checked entirely in the browser and never sent to the server — so it simply doesn't exist from the API's point of view.
Reconstruct the request
Payload schemaNetwork exports don't capture request bodies, so the exact field names — protocolId, outputType, identifierType, identifier, date — were recovered from the bundle's submit function and confirmed against live responses.
Speak JSON, not SOAP
Content negotiationThe same endpoint returns SOAP XML by default; sending the right Accept header flips it to clean JSON. A small detail that turned a parsing nightmare into a one-line extraction.
One request, done right
The final call is deliberately unremarkable — which is the point. It carries the application token from the frontend, asks for JSON, and sends the identifier and today's date.
POST https://api.fbr.gov.pk/iris2ovs/v1/getdata
Authorization: Bearer <application-jwt>
Accept: application/json # without this, FBR replies in SOAP XML
{
"protocolId": "1004",
"outputType": "4",
"identifierType": "CNIC", # or NTN / Passport No. / Reg/Inc. No.
"identifier": "42201XXXXXXX",
"date": "05,Aug,2026"
}The endpoint and token were never meant to be found — they live inside FBR's own Angular bundle, which the browser downloads on every visit.
Turning HTML-in-JSON into clean fields
FBR returns the answer as a blob of HTML wrapped in JSON. The client parses the labels out of that markup into a tidy, typed object ready to drop into a database or KYC flow.
Built for one — or a whole list
The single lookup is a zero-dependency script. On top of it sits a bulk runner designed for large CSVs — because real KYC work is a spreadsheet of thousands of IDs, not one at a time.
Arham Mirkar
Founder & Data Engineer, DataLayer
“My favorite part of this one is that there's almost no code. I spent a day reading someone else's minified JavaScript, found that the captcha was theater, and the actual client fit on a page. Good reverse-engineering usually makes the final solution look obvious.”
Technology
| Layer | Approach |
|---|---|
| Discovery | Chrome net-export capture, custom log-trimming scripts, Angular bundle analysis |
| The insight | Client-side-only captcha, application Bearer JWT lifted from the frontend, JSON vs SOAP content negotiation |
| Client | Zero-dependency Node.js (native fetch), single-lookup CLI, regex field extraction |
| Bulk | Streaming CSV, 50-worker concurrency, 3× retry with backoff + jitter, resumable output |
| Maintenance | Token-refresh helper that re-scrapes the live IRIS bundle when FBR rotates the key |
This is the engine behind DataLayer's Tax Verification API — the productized, hosted version of the same capability.
Got a system that's locked behind a screen?
If a human can pull the data through a browser, it can usually be turned into a clean, programmatic integration. Let's find the door.