Procore App · working prototype

RFI Converter

Generates a Procore RFI onto the owner’s own form — by filling their PDF, not by rebuilding it.

Built on the Procore App platform: a side panel in the RFI tool, a full-screen project tool, OAuth as the signed-in user.

The problem

Public owners mandate their document formats. A DOT, a school district, a municipal authority — the specification prescribes the RFI form, and the contract requires submissions on that form. Procore’s native RFI export is not it.

So the RFI is raised in Procore and then retyped into the owner’s Word or PDF template by hand. The retyped copy becomes the contract record, which means transcription errors land in the contract file, and the effort repeats for every RFI on every job.

The approach

Don’t rebuild the owner’s form. Fill it.

The owner’s blank PDF is kept as the background and values are stamped onto it. Fidelity is exact by construction — the printed layout is theirs, so it cannot drift.

The obvious alternative is to reconstruct each form as a Word template. That was tried first, and it is where fidelity quietly dies: column widths shift, rules collapse, and no validation can detect it, because a template that renders wrongly is still a structurally valid document. Stamping removes that entire failure mode.

How it works

  1. Upload the owner’s blank form. Any PDF. It is validated as static — scripts, embedded files and auto-run actions are rejected.
  2. The app reads its geometry. Captions, rules and boxes are extracted and matched to RFI fields against a fixed catalogue. Deterministic, no language model: the same form always maps the same way.
  3. A person confirms the placement. Proposed fields are drawn over the rendered form and can be dragged onto the right blank. Anything the matcher is unsure of prints nothing until it is confirmed — a blank field is recoverable, a confidently wrong one on a contract document is not.
  4. Generate from any RFI in the project, from the side panel, in a couple of clicks.

Inside Procore

Side panel

Opens alongside the RFI tool. Pick an RFI, pick a form, generate.

Full-screen tool

Upload owner forms, place fields visually, manage them per project.

Signed in as you

Three-legged OAuth, so it sees exactly what the logged-in user sees.

Per project

App configurations carry each project’s number, contract and forms.

What the platform taught me

Several of these are not in the documentation. Each was settled by instrumenting the app and reading what Procore actually sent, rather than assuming.

A side panel receives no record context.

Not in the URL, not over postMessage. The official iframe helper is an authentication helper only. The project has to reach the app another way.

Only app-declared parameters interpolate, with {{double}} braces.

{single} passes through as literal text. There are no built-in context tokens.

App configurations are per component and per project.

Which turns out to be the mechanism that makes multi-project work possible — each project’s configuration carries its own values.

A manifest version bump can silently drop the service account’s project access.

Permissions still read as correct; the account is simply no longer in the project directory. It presents as a 403 with a valid token, and list_projects returning zero is the tell.

Procore rotates refresh tokens.

Persist the rotated one or the next request replays a spent token and the session dies minutes after sign-in.

How it is built

Python and FastAPI on Cloud Run. pdfplumber reads form geometry; PyMuPDF stamps the values. No Office runtime is involved, which keeps the image near 200 MB and removes a whole class of rendering drift.

Credentials live in Secret Manager, sessions are encrypted cookies because the service scales to zero across instances, and uploaded forms are stored partitioned by company and project so no tenant can see another’s. The same modules back a command-line tool and the web app; roughly 170 tests and a clean type check.

The matcher has been exercised against real owner forms — the Toronto Transit Commission, New York State DOT, USACE (ENG 6108), NAVFAC and the National Park Service — each of which broke it in a different way before it handled them.

What it does not do yet