I'm reminded of the Xerox JBIG2 bug back in ~2013, where certain scan settings could silently replace numbers inside documents, and bad construction-plans were one of the cases that led to it being discovered. [0]
It wasn't overt OCR per se, end-user users weren't intending to convert pixels to characters or vice-versa.
I have to make a BOM and oh boy I hate my job
Love to give it to an arc client, not sure who the right person to implement this would be? Hmm…
Full context and details: https://www.dkriesel.com/en/blog/2013/0802_xerox-workcentres...
https://cal.com/anchorgrid/anchorgrid-external-meeting?durat...
The generalization problem you're pointing at is real and it's the hardest part of this. Our approach is to keep the detection scope tight — rather than trying to generalize across every firm's conventions, we train on a small but high-quality set of fixtures and optimize for precision within that scope.
The result is high confidence outputs on the elements we support, rather than mediocre coverage across everything.
We're expanding the detection surface incrementally as we validate accuracy division by division!
Also do doors, windows, and mechanical equipment.
dm, and I can include you in the next preview.
Let me know if you find it useful or have any questions, happy to help.
A lot of them are "archival" so I'm pretty OOL
The world in which metadata is a common thing attached to any file doesn't exist, and probably never will, no matter how much you try to improve CAD work flow.
It is telling that so many of the comments here assume the person with a thing that is not the most practical would be easily able to request thing in a different format. The assumption that the person with the inconvenient thing would never have thought to ask if more convenient thing was available and just willfully toiling with the inconvenient thing is kind of insulting.
There's nothing about PDFs or image formats that prevent anyone from doing OCR. The reason construction documents are difficult to OCR is because OCR models are not well trained for them, and they're very technical documents where small details are significant. It doesn't have anything to do with the file format
The challenge we kept running into is that construction drawings in the wild aren’t always that clean. Unresolved xrefs, exploded dynamic blocks, version incompatibilities, SHX font substitutions — by the time a PDF hits a GC’s desk it’s often the only reliable artifact left. The CAD source may not even be available.
That’s why we see vision becomes the more pragmatic path — not because it’s more precise than structured CAD parsing, but because PDFs are the actual lingua franca of construction. Every firm, every trade, every discipline hands off PDFs. So we made a bet on meeting the document where it actually lives.
On consistency and reproducibility — that’s a real challenge with vision models. Our approach is to keep detection scope narrow and validate confidence scores on every output rather than trying to generalize broadly. Happy to go deeper on that if useful.
Docs/Endpoints/POST /drawings/detection/doors
POST/v1/drawings/detection/doors
Detect doors in architectural floor-plan PDFs. Accepts a previously uploaded document_id, enqueues inference, and returns a job you poll for results. Detections are returned as bounding boxes in PDF coordinate space.
Floor plansAsync · 2022 credits / page
Input


Auth via X-API-Key header. Body is JSON — this endpoint does not accept file uploads directly.
document_idreq
string (UUID)
ID of the uploaded PDF. Must belong to this account and not be expired.
page_numbers
int[]
1-based page indices to scan. Omit to scan all pages. Out-of-range values are skipped by the worker but still billed.
webhook_url
string
URL to POST the completed job payload to. Delivered on developer, pro, and enterprise tiers only.
ℹ
Credits are charged on submission based on len(page_numbers) (or the document's total page count when omitted) — not on pages that actually contain doors. Send only valid page indices to avoid over-billing.
curl -X POST https://api.anchorgrid.ai/v1/drawings/detection/doors \ -H "X-API-Key: " \ -H "Content-Type: application/json" \ -d '{ "document_id": "550e8400-e29b-41d4-a716-446655440000", "page_numbers": [1, 2, 3] }'
The job is enqueued immediately. Poll GET /v1/jobs/{job_id} until status is complete or failed.
job_id
string (UUID)
Use this to poll for results.
status
string
Always queued on this response.
poll_url
string
Path only — prepend https://api.anchorgrid.ai to build the full URL.
When status === "complete" and model === "door-detector", the result field on the job contains:
document_id
string
UUID of the source document.
doors
array
Filtered list of door detections. Each item has id, page, and bbox.
doors[].id
string
Stable identifier — "door_" + 12 hex chars.
doors[].page
integer
1-based PDF page index where the door was detected.
doors[].bbox
object
Axis-aligned bounding box in PDF coordinate space: x1, y1, x2, y2.
doors_found
integer
Count of items in doors after server-side geometry filtering.
pages_analyzed
integer
Number of pages the worker actually scanned.
model_version
string
e.g. door-detector-v1.0.0
processing_time_ms
integer
Wall time for the inference task.
ℹ
The doors list is post-filtered by a geometry and median-area pipeline before being returned. doors_found always reflects the filtered count — raw unfiltered counts are not exposed.
Cost
2 credits × pages billed
Rate limit
Tier RPM (5 / 60 / 120 / 300)
free
Lifetime credit cap — 402 FREE_TIER_LIMIT_REACHED when exceeded.
developer / pro
Monthly pool — 429 QUOTA_EXCEEDED when exceeded.
enterprise
No quota check.
Rate-limit 429s include retry_after_seconds in the body. Quota 429s and rate-limit 429s return the same status code — check the error body to distinguish them.
401
Missing or invalid X-API-Key.
402
Free tier lifetime credit cap reached.
404
document_id not found or expired.
422
Validation error — malformed UUID or invalid body.
429
Rate limit or monthly quota exceeded.
Response Preview
202 OK
{ "job_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "status": "queued", "poll_url": "/v1/jobs/7c9e6679-7425-40de-944b-e07fc1f90ae7" }