Add AI plan review to your product
Your server calls our API with a secret key; your users see results through embeddable hosted screens — no PlanSight login required for them. Every finding is cited to the exact spot on the sheet. No competitor offers a developer API like this.
Overview
A job is one plan set. You create a job, upload the PDF, start a scan, then read findings — or embed our hosted screens so your users never leave your app. The whole loop is server-to-server plus optional iframes.
Authentication
Send your key on every server-to-server call. Keep it server-side — never ship it to a browser. Each key is scoped to its own jobs; another partner's job id returns 404.
Authorization: Bearer ps_live_xxxxxxxxxxxxxxxxxxxxxxxxInvalid key → 401; rate limited → 429 with a Retry-After header. Errors are JSON:
{ "error": { "code": "...", "message": "..." } }Quickstart — upload a plan and get results
The full flow, end to end:
# 1. Create a job
curl -X POST https://YOUR_PLANSIGHT_HOST/api/v1/jobs \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"name":"123 Main St — bid #14"}'
# -> { "jobId": "...", "versionId": "..." }
# 2. Register the PDF -> get a presigned upload URL
curl -X POST https://YOUR_PLANSIGHT_HOST/api/v1/jobs/$JOB/files \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"fileName":"plans.pdf","fileSize":8421000,"contentType":"application/pdf"}'
# -> { "fileId": "...", "uploadUrl": "https://s3..." }
# 3. PUT the raw bytes to the presigned URL
curl -X PUT "$UPLOAD_URL" -H "Content-Type: application/pdf" --data-binary @plans.pdf
# 4. Start the scan
curl -X POST https://YOUR_PLANSIGHT_HOST/api/v1/jobs/$JOB/scan -H "Authorization: Bearer $KEY"
# 5. Poll status until complete (~minutes)
curl https://YOUR_PLANSIGHT_HOST/api/v1/jobs/$JOB -H "Authorization: Bearer $KEY"
# -> { "jobId": "...", "status": "...", "pipeline": { "currentStage": "...", ... } }
# 6. Read findings
curl https://YOUR_PLANSIGHT_HOST/api/v1/jobs/$JOB/findings -H "Authorization: Bearer $KEY"
# -> { "findings": [ { "severity": "...", "rationale": "...", "evidenceAnchors": [...] } ] }Also available: GET /api/v1/jobs/{jobId}/export/csv (findings CSV) and GET /api/v1/jobs/{jobId}/files/{fileId}/annotated (presigned URL to the marked-up PDF).
Show results to your users (embedded screens)
Mint a short-lived signed link from your server, then drop it in an <iframe>. Your user needs no PlanSight account. Links expire in ~30 minutes and are scoped to one screen + one job — mint fresh on demand.
curl -X POST https://YOUR_PLANSIGHT_HOST/api/v1/embed \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"screen":"job","jobId":"'$JOB'"}'
# -> { "url": "https://.../embed/job/JOB?t=SIGNED", "expiresAt": 1733... }loginYour PlanSight dashboard — all your jobs. No jobId.jobUpload + the marked-up plan and findings for one job.chatjobChat: ask questions about the plan, AI answers.jobChat from your own UI
Ask anything about the uploaded set; answers come back grounded with citations.
curl -X POST https://YOUR_PLANSIGHT_HOST/api/v1/jobs/$JOB/chat \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"message":"What setbacks does the site plan call out?"}'
# -> { "answer": "...", "citations": [ { "page": 4, "sheetType": "...", "excerpt": "..." } ] }API reference
All endpoints live under https://plansight.xyz/api/v1. The machine-readable contract is the OpenAPI spec.
/api/v1/jobsCreate a job (one plan set). Returns jobId + versionId./api/v1/jobs/{jobId}Job status + pipeline stage. Poll until terminal./api/v1/jobs/{jobId}/filesRegister a PDF; returns a presigned upload URL./api/v1/jobs/{jobId}/scanStart the review pipeline for the job./api/v1/jobs/{jobId}/findingsFindings with severity, rationale, and evidence anchors./api/v1/jobs/{jobId}/export/csvAll findings as CSV./api/v1/jobs/{jobId}/files/{fileId}/annotatedPresigned URL to the marked-up PDF./api/v1/jobs/{jobId}/chatjobChat — ask a question, get a cited answer./api/v1/embedMint a short-lived signed link for an embedded screen./api/v1/pingAuth + connectivity check.API Explorer
Pick an endpoint, edit the params, and watch the request build across cURL, JavaScript, and Python. Hit Run sample to see a representative response. Real calls authenticate with your ps_live key server-side.
Create a job (one plan set).
curl -X POST https://arch-ai.expertresearch.net/api/v1/jobs \
-H "Authorization: Bearer $PLANSIGHT_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"123 Main St — bid #14"}'ps_live key server-sideGetting a key
PlanSight mints your ps_live_… key and shares it with you once. Treat it like a password; rotate by asking for a new one (the old one is revoked). Request a key →
Building this with an AI coding agent?
Paste the prompt below into your coding agent — it has everything: auth, the upload→scan→results flow, jobChat, and the three embeddable screens. Raw copy at https://plansight.xyz/developers/prompt.
[PlanSight Partner API v1.0.0 · build 7acb0c07c2f1a3ee0ae1476b4d7bf3f05dc96bba · https://plansight.xyz]
You are adding a "PlanSight" integration to our construction job-management app
(we bid, estimate, and pay for work). PlanSight is an AI building-plan code-review
service. Your job: let our users upload plans, see PlanSight's scan results, and
ask questions about a plan — all inside our app.
AUTHORITATIVE DOCS (read these first, in full):
- Guide: https://plansight.xyz/developers
- OpenAPI: https://plansight.xyz/api/v1/openapi.json (every endpoint + exact request/response schemas)
CREDENTIALS
- We have a PlanSight API key in the server env var PLANSIGHT_API_KEY (format ps_live_...).
- It is a SERVER-SIDE SECRET. NEVER send it to the browser, log it, or commit it.
- Every server-to-server call: header Authorization: Bearer $PLANSIGHT_API_KEY
- Our PlanSight account owns everything we send; one "job" in PlanSight === one of our jobs.
BUILD THE FOLLOWING
1) A small server-side PlanSight client (e.g. lib/plansight.ts) that wraps:
POST https://plansight.xyz/api/v1/jobs -> { jobId, versionId } (create)
POST https://plansight.xyz/api/v1/jobs/{jobId}/files -> { fileId, uploadUrl } (then PUT the PDF bytes to uploadUrl with Content-Type: application/pdf)
POST https://plansight.xyz/api/v1/jobs/{jobId}/scan -> starts the scan (async)
GET https://plansight.xyz/api/v1/jobs/{jobId} -> { status, pipeline } (poll until complete/failed)
GET https://plansight.xyz/api/v1/jobs/{jobId}/findings -> { findings: [...] }
POST https://plansight.xyz/api/v1/jobs/{jobId}/chat -> { answer, citations }
POST https://plansight.xyz/api/v1/embed { screen, jobId? } -> { url, expiresAt } (signed hosted-screen link)
2) On each of our jobs, store the PlanSight jobId. Add an "Upload plans for review"
action: create a PlanSight job, get a presigned URL, PUT the PDF, then call scan.
Track status by polling GET /api/v1/jobs/{jobId} (or show our own progress).
3) Add a "PlanSight" screen/tab to each job offering THREE things (use the hosted
screens — do NOT rebuild PlanSight's UI). For each, call POST /api/v1/embed from
OUR SERVER (with the API key), then render the returned url in an <iframe>:
- results: POST /api/v1/embed { screen: "job", jobId } -> iframe the url (marked-up plan + findings, with upload)
- jobChat: POST /api/v1/embed { screen: "chat", jobId } -> iframe the url (ask questions, AI answers)
- a "Log in to PlanSight" button: POST /api/v1/embed { screen: "login" } -> open the url (their full PlanSight dashboard)
Embed links expire in ~30 minutes and are scoped to one screen + one job — mint them
fresh, server-side, when the user opens the screen. NEVER mint them in the browser.
4) (Optional, great for a bid/estimate app) Also pull GET /api/v1/jobs/{jobId}/findings
server-side and show a NATIVE summary on the job card — counts by severity and any
cost impact — with an "Open full report" button that opens the embedded results screen.
RULES
- Match the exact shapes in the OpenAPI spec. Handle 401 (bad key), 404 (job not found
/ not ours), and 429 (rate limited — respect the Retry-After header).
- Keep the API key server-side always; the browser only ever sees short-lived embed URLs.
- Scans are asynchronous (minutes); design the UI around "submitted -> processing -> ready".
Confirm your integration plan, then implement it incrementally with tests.