API reference
Groundbook API
Every route the website uses, open to your own code. Requests act as your account with exactly your permissions. Each endpoint shows curl and the gb command line; assistants reach the same routes through the tools named on it.
Authentication
Create an API key in Connectors → API keys and send it as a bearer token. A read-only key can call GET routes only. Keys never carry admin powers, and you can revoke one at any time.
curl "https://app.groundbook.ai/api/auth/me" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"Assistants use OAuth 2.1 instead: authorization code with PKCE, dynamic client registration, and rotating refresh tokens. Discovery is at /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource; the MCP endpoint is https://app.groundbook.ai/api/mcp. An OAuth access token works on every route below in the same way as a key.
The base URL is https://app.groundbook.ai. Bodies are JSON; ids are UUIDs; times are ISO 8601 in UTC.
Errors
Every error is JSON with one plain-English error message you can show to a person.
{ "error": "Wait for every file to finish analyzing before payment." }| Status | Type | Meaning |
|---|---|---|
| 400 | Bad request | A field is missing or out of range. The message says which. |
| 401 | Unauthorized | No key, a revoked key, or an expired OAuth token. Refresh the token or create a new key. |
| 403 | Forbidden | A read-only key on a write route, or an action only the owner can take. |
| 404 | Not found | The id does not exist or your account cannot open it. We do not say which. |
| 409 | Conflict | The check is past editing, payment is in progress, or someone needs project access first (code: "project_access_required"). |
| 429 | Too many requests | Only the OAuth token route and anonymous uploads send this. Wait a minute and retry. |
Account
Who the key or token belongs to.
GET/api/auth/me
The signed-in account: email, organization, and credit balance.
Assistant tools: get_me
curl "https://app.groundbook.ai/api/auth/me" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb whoami{
"user": {
"id": "An9o6aC0tnYvuUqnsIwEp1HLjuk2",
"email": "you@example.com",
"displayName": "Your Name",
"isSuperAdmin": false,
"organization": {
"id": "6c93e7de-cbd9-44c8-a5dd-edafca9138a0",
"name": "Example Engineering",
"role": "admin",
"billingMode": "account"
},
"billing": {
"scope": "account",
"balanceCents": 12000
}
}
}Projects
A project holds one set of drawings and its latest check. Every project you can open on the site is here, with the same permissions.
GET/api/projects
Projects this account can open, newest first.
Assistant tools: list_projects
| Parameter | Type | Description |
|---|---|---|
qquery | string | Text to match against the project address or file names. |
statusquery | draft | processing | ready | Repeat to allow several statuses. |
pagequery | integer | Page number, starting at 1. 20 projects per page. |
ownerquery | string | Owner user id; repeat for several. Only useful inside an organization. |
curl "https://app.groundbook.ai/api/projects?status=ready" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb list_projects --status ready{
"projects": [
{
"id": "8c0d0499-7e63-40f6-812f-0b080be21449",
"address": "2465 Semlin Drive, Vancouver, BC",
"isOwner": true,
"ownerEmail": "you@example.com",
"accessSource": "owner",
"checkId": "7100d123-0aac-41eb-898d-98679e1f9694",
"checkStatus": "complete",
"customerStatus": "ready",
"documentCount": 2,
"issueCount": 42,
"primaryDocumentName": "B&S_-_Structural_Dwgs.pdf",
"createdAt": "2026-08-21T01:40:12.000Z",
"updatedAt": "2026-08-21T01:52:23.506Z"
}
],
"owners": [
{
"id": "An9o6aC0tnYvuUqnsIwEp1HLjuk2",
"email": "you@example.com",
"displayName": "Your Name"
}
],
"pagination": {
"page": 1,
"pageSize": 20,
"totalPages": 1,
"totalCount": 1
}
}POST/api/projects201
Creates a draft project with its first check. Name it and add files next.
Assistant tools: create_project
curl -X POST "https://app.groundbook.ai/api/projects" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb create_project --address "12 Main St" --review-instructions "Check the framing plan against the foundation plan."{
"projectId": "0b1b0ef3-9f2d-4c1a-8d0e-3f2a5a6b7c8d",
"checkId": "fed043d1-a9c8-4eab-bd26-047af9d6d34b",
"address": null,
"reviewInstructions": "Find conflicts, inconsistencies, and missing information across the drawings.",
"reviewInstructionsAutoGenerated": true,
"reviewInstructionsTitle": null,
"codeCheckEnabled": true,
"priceCents": 10000
}GET/api/projects/{projectId}
One project with its latest check's settings and totals.
Assistant tools: get_project, update_project
| Parameter | Type | Description |
|---|---|---|
projectIdpath | uuid required | The project id. |
curl "https://app.groundbook.ai/api/projects/PROJECT_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb get_project --project-id PROJECT_ID{
"project": {
"id": "8c0d0499-7e63-40f6-812f-0b080be21449",
"address": "2465 Semlin Drive, Vancouver, BC",
"organizationAccessEnabled": false,
"projectDisciplines": [],
"projectIssueStatuses": [
"Needs RFI"
],
"isOwner": true,
"accessSource": "owner",
"ownerEmail": "you@example.com",
"ownerDisplayName": "Your Name",
"updatedAt": "2026-08-21T01:52:23.506Z",
"checkId": "7100d123-0aac-41eb-898d-98679e1f9694",
"checkStatus": "complete",
"reviewInstructions": "Review these plans for coordination conflicts.",
"reviewInstructionsAutoGenerated": false,
"reviewInstructionsTitle": "Coordination",
"codeCheckEnabled": true,
"priceCents": 10000,
"paymentMethod": "credits",
"creditsAppliedCents": 10000,
"paidAt": "2026-08-21T01:52:23.506Z",
"documentCount": 2,
"pageCount": 59,
"codeCount": 0,
"primaryDocumentName": "B&S_-_Structural_Dwgs.pdf"
}
}PATCH/api/projects/{projectId}
Renames a project.
Assistant tools: create_project, update_project
| Parameter | Type | Description |
|---|---|---|
projectIdpath | uuid required | The project id. |
addressbody | string | null required | The new address or name, up to 500 characters. null clears it. |
curl -X PATCH "https://app.groundbook.ai/api/projects/PROJECT_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"address":"12 Main St"}'gb update_project --project-id PROJECT_ID --address "12 Main St"{
"address": "12 Main St"
}DELETE/api/projects/{projectId}204
Permanently deletes a project with its files and issues. Owner only. This cannot be undone.
Assistant tools: delete_project
| Parameter | Type | Description |
|---|---|---|
projectIdpath | uuid required | The project id. |
curl -X DELETE "https://app.groundbook.ai/api/projects/PROJECT_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb delete_project --project-id PROJECT_ID --yesNo body.- 409 when a payment for the project is still being completed.
PATCH/api/projects/{projectId}/shares
Lets everyone in the owner's organization open the project, or stops that.
Assistant tools: share_project
| Parameter | Type | Description |
|---|---|---|
projectIdpath | uuid required | The project id. |
organizationAccessEnabledbody | boolean required | true to open the project to the organization. |
curl -X PATCH "https://app.groundbook.ai/api/projects/PROJECT_ID/shares" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"organizationAccessEnabled":true}'gb share_project --project-id PROJECT_ID --organization-access true{
"organizationAccessEnabled": true
}DELETE/api/projects/{projectId}/invitations/{invitationId}204
Cancels a pending invitation.
Assistant tools: remove_project_share
| Parameter | Type | Description |
|---|---|---|
projectIdpath | uuid required | The project id. |
invitationIdpath | uuid required | The invitation id, from the shares list. |
curl -X DELETE "https://app.groundbook.ai/api/projects/PROJECT_ID/invitations/INVITATION_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb remove_project_share --project-id PROJECT_ID --invitation-id INVITATION_ID --yesNo body.POST/api/projects/{projectId}/statuses201
Adds a custom issue status to the project, next to open, reviewed, resolved, and dismissed.
Assistant tools: update_project
| Parameter | Type | Description |
|---|---|---|
projectIdpath | uuid required | The project id. |
statusbody | string required | The status name, up to 80 characters. |
curl -X POST "https://app.groundbook.ai/api/projects/PROJECT_ID/statuses" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"Needs RFI"}'gb update_project --project-id PROJECT_ID --add-issue-status "Needs RFI"{
"status": "Needs RFI"
}POST/api/projects/{projectId}/disciplines201
Adds a discipline the project can tag issues with.
Assistant tools: update_project
| Parameter | Type | Description |
|---|---|---|
projectIdpath | uuid required | The project id. |
disciplinebody | string required | The discipline name, up to 80 characters. |
curl -X POST "https://app.groundbook.ai/api/projects/PROJECT_ID/disciplines" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"discipline":"Fire protection"}'gb update_project --project-id PROJECT_ID --add-discipline "Fire protection"{
"discipline": "Fire protection"
}Checks
A check is one review run over a project's files. Set what it should focus on, add codes, then pay and start it.
GET/api/checks/{checkId}
Where the check is: draft, waiting for payment, a percentage while it runs, complete, or failed.
progressPercent weighs every stage the same: a started stage counts half, a finished one counts in full. It is 100 once the check is complete.
Assistant tools: get_project
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | The check id, from the project. |
curl "https://app.groundbook.ai/api/checks/CHECK_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb get_project --project-id PROJECT_ID{
"check": {
"id": "7100d123-0aac-41eb-898d-98679e1f9694",
"projectId": "8c0d0499-7e63-40f6-812f-0b080be21449",
"status": "processing",
"progressPercent": 43,
"documentCount": 2,
"pageCount": 59,
"issueCount": 0,
"priceCents": 10000,
"paidAt": "2026-08-21T01:52:23.506Z",
"createdAt": "2026-08-21T01:40:12.000Z",
"updatedAt": "2026-08-21T02:10:00.000Z",
"url": "https://app.groundbook.ai/projects/8c0d0499-7e63-40f6-812f-0b080be21449"
}
}GET/api/checks/{checkId}/review-instructions
What the check focuses on, and the instructions you used on recent projects.
Assistant tools: create_project, set_review_instructions
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | The check id. |
curl "https://app.groundbook.ai/api/checks/CHECK_ID/review-instructions" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb api GET /api/checks/CHECK_ID/review-instructions{
"reviewInstructions": "Check the framing plan against the foundation plan for grid mismatches.",
"reviewInstructionsAutoGenerated": false,
"reviewInstructionsTitle": "Framing vs foundation",
"codeCheckEnabled": true,
"recentReviewInstructions": []
}PATCH/api/checks/{checkId}/review-instructions
Sets what the check focuses on and whether it checks against building codes. Draft checks only.
Assistant tools: create_project, set_review_instructions
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | The check id. |
reviewInstructionsbody | string required | 20 to 4000 characters. |
reviewInstructionsTitlebody | string | null required | A short title, up to 80 characters, or null. |
autoGeneratedbody | boolean required | false when a person wrote the instructions. |
codeCheckEnabledbody | boolean required | Whether to check against building codes. |
curl -X PATCH "https://app.groundbook.ai/api/checks/CHECK_ID/review-instructions" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reviewInstructions":"Check the framing plan against the foundation plan for grid mismatches.","reviewInstructionsTitle":"Framing vs foundation","autoGenerated":false,"codeCheckEnabled":true}'gb set_review_instructions --project-id PROJECT_ID --review-instructions "Check the framing plan against the foundation plan for grid mismatches."{
"reviewInstructions": "Check the framing plan against the foundation plan for grid mismatches.",
"reviewInstructionsTitle": "Framing vs foundation",
"codeCheckEnabled": true
}- 409 once payment has started; the check is no longer editable.
POST/api/checks/{checkId}/code-sources
Adds a building code by public URL, or marks one of the check's files as the code book.
Assistant tools: add_code_source
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | The check id. |
codeNamebody | string required | The code's name, up to 300 characters. |
sourceUrlbody | string | A public URL of the code. Give this or checkDocumentId. |
checkDocumentIdbody | uuid | One of the check's files that is the code book. |
curl -X POST "https://app.groundbook.ai/api/checks/CHECK_ID/code-sources" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"codeName":"2022 California Building Code","sourceUrl":"https://example.com/cbc-2022.pdf"}'gb add_code_source --project-id PROJECT_ID --code-name "2022 California Building Code" --source-url https://example.com/cbc-2022.pdf{
"source": {
"codeName": "2022 California Building Code",
"sourceType": "url",
"sourceStatus": "queued",
"sourceUrl": "https://example.com/cbc-2022.pdf"
},
"priceCents": 12000
}DELETE/api/checks/{checkId}/code-sources
Removes a building code from the check.
Assistant tools: remove_code_source
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | The check id. |
codeNamequery | string required | The code's name. |
curl -X DELETE "https://app.groundbook.ai/api/checks/CHECK_ID/code-sources?codeName=2022+California+Building+Code" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb remove_code_source --project-id PROJECT_ID --code-name "2022 California Building Code" --yes{
"priceCents": 10000
}POST/api/checks/{checkId}/checkout
Pays for and starts the check. Credits or the free first project are used when available; otherwise you get a payment link.
Assistant tools: start_check
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | The check id. |
curl -X POST "https://app.groundbook.ai/api/checks/CHECK_ID/checkout" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'gb start_check --project-id PROJECT_ID{
"paid": true,
"paymentMethod": "credits",
"projectId": "8c0d0499-7e63-40f6-812f-0b080be21449"
}- When payment is needed the response is { paid: false, url } and the check starts as soon as the payment completes.
- 409 with a plain-English reason when a file is still analyzing, no file is marked checked, the instructions are missing, or the check is already paid.
Files
PDFs in a check, and PDFs saved for reuse. Uploads go straight to storage through a signed URL.
GET/api/checks/{checkId}/documents
The check's files with their analysis status, plus its code sources and price.
Assistant tools: get_project, add_saved_files_to_project
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | The check id. |
curl "https://app.groundbook.ai/api/checks/CHECK_ID/documents" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb get_project --project-id PROJECT_ID{
"documents": [
{
"id": "73808823-a773-4917-a5a6-24168948f498",
"checkDocumentId": "0dcf2ea3-e845-417a-9aba-1b1ce9ea092c",
"name": "B&S_-_Structural_Dwgs.pdf",
"sizeBytes": "48213377",
"pages": 42,
"kind": "drawing",
"saved": false,
"reviewRole": "checked",
"processingStatus": "complete",
"codeMatchingStatus": null
}
],
"codeSources": [],
"projectAddress": "2465 Semlin Drive, Vancouver, BC",
"codeCheckEnabled": true,
"priceCents": 10000
}POST/api/uploads201
Step 1 of an upload: reserves a file and returns a signed URL to PUT the PDF to.
PUT the bytes to uploadUrl with the returned headers, then call the complete route. The CLI's gb upload does all three steps.
| Parameter | Type | Description |
|---|---|---|
checkIdbody | uuid required | A draft check. |
fileNamebody | string required | Must end in .pdf. |
sizeBytesbody | integer required | Up to 1 GB. |
curl -X POST "https://app.groundbook.ai/api/uploads" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"checkId":"fed043d1-a9c8-4eab-bd26-047af9d6d34b","fileName":"plans.pdf","sizeBytes":1048576}'gb upload plans.pdf --project PROJECT_ID{
"documentId": "6459b03a-9122-45f3-a915-7949704fdb2d",
"uploadUrl": "https://…signed…",
"headers": {
"Content-Type": "application/pdf"
}
}POST/api/uploads/{documentId}/complete201
Step 3 of an upload: tells us the PDF is in storage so analysis starts.
| Parameter | Type | Description |
|---|---|---|
documentIdpath | uuid required | From the create-upload response. |
checkIdbody | uuid required | The same draft check. |
originalNamebody | string required | The file name to show. |
sizeBytesbody | integer required | The size you uploaded. |
codeNamebody | string | Name the file as a code book instead of a drawing set. |
curl -X POST "https://app.groundbook.ai/api/uploads/DOCUMENT_ID/complete" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"checkId":"fed043d1-a9c8-4eab-bd26-047af9d6d34b","originalName":"plans.pdf","sizeBytes":1048576}'gb upload plans.pdf --project PROJECT_ID{
"checkDocumentId": "0dcf2ea3-e845-417a-9aba-1b1ce9ea092c",
"runId": "5925f763-677f-4b04-84ea-9ccd12995f82",
"runStatus": "queued"
}POST/api/checks/{checkId}/documents201
Adds saved PDFs to a draft check without uploading them again.
Assistant tools: add_saved_files_to_project
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | A draft check. |
documentIdsbody | uuid[] required | 1 to 50 saved file ids. |
curl -X POST "https://app.groundbook.ai/api/checks/CHECK_ID/documents" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"documentIds":["73808823-a773-4917-a5a6-24168948f498"]}'gb add_saved_files_to_project --project-id PROJECT_ID --document-ids DOC_ID_1,DOC_ID_2{
"documents": [
{
"checkDocumentId": "0dcf2ea3-e845-417a-9aba-1b1ce9ea092c",
"documentId": "73808823-a773-4917-a5a6-24168948f498",
"name": "B&S_-_Structural_Dwgs.pdf"
}
]
}PATCH/api/check-documents/{checkDocumentId}
Marks a file as checked or reference, or sets its file type. Draft checks only.
Assistant tools: set_file_role
| Parameter | Type | Description |
|---|---|---|
checkDocumentIdpath | uuid required | The file's id within the check, from the files list. |
reviewRolebody | checked | reference | checked files are reviewed for issues; reference files are context only. |
fileTypebody | string | A file type such as drawing, specification, or code. |
curl -X PATCH "https://app.groundbook.ai/api/check-documents/CHECK_DOCUMENT_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reviewRole":"checked"}'gb set_file_role --check-document-id CHECK_DOCUMENT_ID --role checked{
"fileType": null,
"reviewRole": "checked",
"codeMatchingStatus": null
}DELETE/api/check-documents/{checkDocumentId}204
Removes a file from a draft check. An upload is deleted; a saved file stays in the library.
Assistant tools: remove_file
| Parameter | Type | Description |
|---|---|---|
checkDocumentIdpath | uuid required | The file's id within the check. |
curl -X DELETE "https://app.groundbook.ai/api/check-documents/CHECK_DOCUMENT_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb remove_file --check-document-id CHECK_DOCUMENT_ID --yesNo body.GET/api/saved-documents
PDFs saved by you or your organization, with the projects that use each one.
Assistant tools: list_saved_files
curl "https://app.groundbook.ai/api/saved-documents" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb list_saved_files{
"organization": {
"id": "6c93e7de-cbd9-44c8-a5dd-edafca9138a0",
"name": "Example Engineering"
},
"documents": [
{
"id": "73808823-a773-4917-a5a6-24168948f498",
"name": "B&S_-_Structural_Dwgs.pdf",
"pages": 42,
"sizeBytes": "48213377",
"scope": "organization",
"projects": [
{
"id": "8c0d0499-7e63-40f6-812f-0b080be21449",
"address": "2465 Semlin Drive, Vancouver, BC"
}
]
}
]
}PATCH/api/documents/{documentId}
Saves a file for reuse, renames it, or changes whether the organization can use it.
| Parameter | Type | Description |
|---|---|---|
documentIdpath | uuid required | The document id. |
savedbody | boolean | true keeps the file after its project; false removes it from the library. |
namebody | string | A new name. |
scopebody | personal | organization | Who may reuse it. Only the person who saved it can change this. |
curl -X PATCH "https://app.groundbook.ai/api/documents/DOCUMENT_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"saved":true,"scope":"organization"}'gb api PATCH /api/documents/DOCUMENT_ID --data '{"saved":true,"scope":"organization"}'{
"saved": true,
"removed": false,
"scope": "organization"
}GET/api/documents/{documentId}/content
The PDF itself. Supports Range requests; add ?download=1 for an attachment.
| Parameter | Type | Description |
|---|---|---|
documentIdpath | uuid required | The document id. |
downloadquery | 1 | Send as an attachment instead of inline. |
curl "https://app.groundbook.ai/api/documents/DOCUMENT_ID/content" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb api GET /api/documents/DOCUMENT_ID/contentThe PDF bytes with Content-Type: application/pdf.Issues
What a check found. Each issue cites the sheets it comes from and carries a status, severity, labels, assignees, and comments.
GET/api/checks/{checkId}/issues
Every issue on a check, most severe first, with references, assignees, and your own feedback.
Assistant tools: list_issues
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | The check id. |
curl "https://app.groundbook.ai/api/checks/CHECK_ID/issues" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb list_issues --project-id PROJECT_ID --severity High --status open{
"issues": [
{
"id": "1f78a5ca-1640-4075-998e-b1495295dcda",
"displayNumber": 1,
"title": "Governing SW3 schedule is unclear between S42 and S43",
"description": "Sheet S42 and sheet S43 both carry a schedule for shear wall SW3 with different bar sizes…",
"severityLabel": "High",
"severityRank": 100,
"disciplines": [
"Structural"
],
"labels": [],
"impact": "The contractor cannot tell which reinforcement to build.",
"recommendation": "Remove one schedule or reference the governing sheet.",
"status": "open",
"assignees": [],
"commentCount": 0,
"feedback": {
"accuracy": null,
"usefulness": null,
"reasons": []
},
"references": [
{
"id": "4d9dabbe-40c4-4e7f-b8b2-e0b4daf32e45",
"documentId": "73808823-a773-4917-a5a6-24168948f498",
"documentName": "B&S_-_Structural_Dwgs.pdf",
"pageIndex": 41,
"pageLabel": "42",
"sheetNumber": "S42",
"referenceLabel": "SW3 schedule",
"citedText": "SW3 … 15M @ 300"
}
]
}
]
}GET/api/issues/{issueId}
One issue in full, with its project.
Assistant tools: get_issue, update_issue, assign_issue
| Parameter | Type | Description |
|---|---|---|
issueIdpath | uuid required | The issue id. |
curl "https://app.groundbook.ai/api/issues/ISSUE_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb get_issue --issue-id ISSUE_ID{
"issue": {
"id": "1f78a5ca-1640-4075-998e-b1495295dcda",
"displayNumber": 1,
"title": "Governing SW3 schedule is unclear between S42 and S43",
"description": "Sheet S42 and sheet S43 both carry a schedule for shear wall SW3 with different bar sizes…",
"severityLabel": "High",
"severityRank": 100,
"disciplines": [
"Structural"
],
"labels": [],
"impact": "The contractor cannot tell which reinforcement to build.",
"recommendation": "Remove one schedule or reference the governing sheet.",
"status": "open",
"assignees": [],
"commentCount": 0,
"feedback": {
"accuracy": null,
"usefulness": null,
"reasons": []
},
"references": [
{
"id": "4d9dabbe-40c4-4e7f-b8b2-e0b4daf32e45",
"documentId": "73808823-a773-4917-a5a6-24168948f498",
"documentName": "B&S_-_Structural_Dwgs.pdf",
"pageIndex": 41,
"pageLabel": "42",
"sheetNumber": "S42",
"referenceLabel": "SW3 schedule",
"citedText": "SW3 … 15M @ 300"
}
],
"checkId": "7100d123-0aac-41eb-898d-98679e1f9694",
"projectId": "8c0d0499-7e63-40f6-812f-0b080be21449",
"projectLabel": "2465 Semlin Drive, Vancouver, BC"
}
}PATCH/api/issues/{issueId}
Changes severity, status, or labels.
Assistant tools: update_issue
| Parameter | Type | Description |
|---|---|---|
issueIdpath | uuid required | The issue id. |
severityLabelbody | High | Medium | Low | The new severity. |
statusbody | string | open, reviewed, resolved, dismissed, or a status saved on the project. |
labelsbody | string[] | Replaces the labels. Up to 20, each up to 40 characters. |
curl -X PATCH "https://app.groundbook.ai/api/issues/ISSUE_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"resolved","labels":["grid","coordination"]}'gb update_issue --issue-id ISSUE_ID --status resolved --labels grid,coordination{
"issue": {
"severityLabel": "High",
"severityRank": 100,
"status": "resolved",
"labels": [
"grid",
"coordination"
]
}
}GET/api/issues/{issueId}/comments
The issue's comments, oldest first, with attachments.
Assistant tools: get_issue
| Parameter | Type | Description |
|---|---|---|
issueIdpath | uuid required | The issue id. |
curl "https://app.groundbook.ai/api/issues/ISSUE_ID/comments" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb get_issue --issue-id ISSUE_ID{
"comments": [
{
"id": "c1",
"body": "Fixed in revision B.",
"author": {
"id": "u2",
"email": "eng@example.com",
"displayName": "Eng"
},
"mentions": [],
"attachments": [],
"createdAt": "2026-09-14T00:00:00.000Z",
"updatedAt": "2026-09-14T00:00:00.000Z"
}
]
}POST/api/issues/{issueId}/comments201
Adds a comment. Mentioned people are emailed; someone outside the project is invited only when you say so.
Assistant tools: comment_on_issue
| Parameter | Type | Description |
|---|---|---|
issueIdpath | uuid required | The issue id. |
bodybody | string required | Up to 4000 characters. |
mentionsbody | { email, displayLabel }[] | People to notify, up to 20. |
grantProjectAccessEmailsbody | string[] | Mentioned emails to invite to the project if they cannot open it. |
attachmentIdsbody | uuid[] | Attachments uploaded through the site. |
curl -X POST "https://app.groundbook.ai/api/issues/ISSUE_ID/comments" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"body":"Fixed in revision B.","mentions":[{"email":"eng@example.com","displayLabel":"eng@example.com"}],"grantProjectAccessEmails":[],"attachmentIds":[]}'gb comment_on_issue --issue-id ISSUE_ID --body "Fixed in revision B." --mentions eng@example.com{
"comment": {
"id": "c2",
"body": "Fixed in revision B.",
"author": {
"id": "u1",
"email": "you@example.com",
"displayName": "Your Name"
},
"mentions": [
{
"email": "eng@example.com",
"displayLabel": "eng@example.com"
}
],
"attachments": [],
"createdAt": "2026-09-14T00:00:00.000Z"
}
}- 409 { code: "project_access_required", people } when a mentioned person cannot open the project and grantProjectAccessEmails does not include them.
POST/api/issues/{issueId}/assignees201
Assigns the issue to someone by email.
Assistant tools: assign_issue
| Parameter | Type | Description |
|---|---|---|
issueIdpath | uuid required | The issue id. |
emailbody | string required | Who to assign. |
grantProjectAccessbody | boolean | Invite them to the project if they cannot open it. Default false. |
curl -X POST "https://app.groundbook.ai/api/issues/ISSUE_ID/assignees" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"eng@example.com","grantProjectAccess":false}'gb assign_issue --issue-id ISSUE_ID --email eng@example.com{
"assignee": {
"id": "a1",
"userId": "u2",
"email": "eng@example.com",
"displayName": "Eng",
"pending": false,
"notificationDelivered": true
},
"notificationDelivered": true
}- 409 { code: "project_access_required", people } when the person cannot open the project; call again with grantProjectAccess: true to invite them.
DELETE/api/issues/{issueId}/assignees/{assigneeId}204
Removes an assignee.
Assistant tools: unassign_issue
| Parameter | Type | Description |
|---|---|---|
issueIdpath | uuid required | The issue id. |
assigneeIdpath | uuid required | From the issue's assignees. |
curl -X DELETE "https://app.groundbook.ai/api/issues/ISSUE_ID/assignees/ASSIGNEE_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb unassign_issue --issue-id ISSUE_ID --assignee-id ASSIGNEE_ID --yesNo body.PATCH/api/issues/{issueId}/feedback
Records whether the issue is correct and useful. One answer per person per issue.
Assistant tools: give_issue_feedback
| Parameter | Type | Description |
|---|---|---|
issueIdpath | uuid required | The issue id. |
accuracybody | correct | incorrect | null required | Whether the finding is right. |
usefulnessbody | useful | not_useful | null required | Whether it helps. |
reasonsbody | string[] required | Any of important, low_importance, strong_evidence, wrong_or_missing_evidence, duplicate, unclear, related_issue. |
curl -X PATCH "https://app.groundbook.ai/api/issues/ISSUE_ID/feedback" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"accuracy":"correct","usefulness":"useful","reasons":["important"]}'gb give_issue_feedback --issue-id ISSUE_ID --accuracy correct --usefulness useful --reasons important{
"feedback": {
"accuracy": "correct",
"usefulness": "useful",
"reasons": [
"important"
]
}
}Exports
A PDF report, marked-up drawings, a Bluebeam FDF, or a CSV of a check's issues. Exports build in the background.
POST/api/checks/{checkId}/exports202
Starts an export. Poll it until it is ready, then download the file.
Assistant tools: export_issues
| Parameter | Type | Description |
|---|---|---|
checkIdpath | uuid required | The check id. |
formatbody | report | markup | fdf | csv required | What to build. |
issueIdsbody | uuid[] | null | Only these issues, in this order. Otherwise every open issue. |
curl -X POST "https://app.groundbook.ai/api/checks/CHECK_ID/exports" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"format":"report"}'gb export_issues --project-id PROJECT_ID --format report{
"export": {
"id": "faaef1d5-91cc-4585-9edb-83b5977af77a",
"status": "queued",
"format": "report",
"fileName": "2465 Semlin Drive issues.pdf",
"progressDone": 0,
"progressTotal": null,
"sizeBytes": null,
"error": null
}
}GET/api/exports/{exportId}
Progress of an export you started.
Assistant tools: get_export
| Parameter | Type | Description |
|---|---|---|
exportIdpath | uuid required | The export id. |
curl "https://app.groundbook.ai/api/exports/EXPORT_ID" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb get_export --export-id EXPORT_ID{
"export": {
"id": "faaef1d5-91cc-4585-9edb-83b5977af77a",
"status": "ready",
"format": "report",
"fileName": "2465 Semlin Drive issues.pdf",
"progressDone": 12,
"progressTotal": 12,
"sizeBytes": 2481920,
"error": null
}
}GET/api/exports/{exportId}/file
The built file. 409 until the export is ready. Files are kept for seven days.
Assistant tools: get_export
| Parameter | Type | Description |
|---|---|---|
exportIdpath | uuid required | The export id. |
curl "https://app.groundbook.ai/api/exports/EXPORT_ID/file" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY"gb download-export EXPORT_ID --out issues.pdfThe file bytes, with Content-Type and Content-Disposition set for the format.Ask
The project assistant as one call: a question in, an answer with references out. It reads the sheets, issues, and schedules the same way the chat on the site does, and uses the project's chat credits.
POST/api/projects/{projectId}/ask
Asks a question about a project and waits for the answer.
When the answer takes longer than waitSeconds, status is running: call again with the conversationId and no question to collect it. Use the same conversationId to keep asking in context.
Assistant tools: ask
| Parameter | Type | Description |
|---|---|---|
projectIdpath | uuid required | The project id. |
questionbody | string | Up to 8000 characters. Omit it to collect a pending answer. |
conversationIdbody | uuid | Continue an earlier conversation. |
waitSecondsbody | integer | 0 to 55. Default 45. |
curl -X POST "https://app.groundbook.ai/api/projects/PROJECT_ID/ask" \
-H "Authorization: Bearer $GROUNDBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"question":"Which sheets have unresolved conflicts?"}'gb ask --project-id PROJECT_ID --question "Which sheets have unresolved conflicts?"{
"conversationId": "28eb6c74-3b02-44d5-b7bf-3f967820e7e9",
"turnId": "36e92139-a0fd-41bd-b911-6ecf03b024cf",
"status": "complete",
"answer": "Three sheets still have open conflicts: S42 and S43 disagree on the SW3 schedule (#1), and S10 conflicts with M-200 on the P2 floor elevation (#6)…",
"message": null,
"links": [
{
"label": "Issue #1",
"href": "https://app.groundbook.ai/projects/8c0d0499-7e63-40f6-812f-0b080be21449/documents/73808823-a773-4917-a5a6-24168948f498?issue=1f78a5ca-1640-4075-998e-b1495295dcda&reference=4d9dabbe-40c4-4e7f-b8b2-e0b4daf32e45"
}
],
"url": "https://app.groundbook.ai/projects/8c0d0499-7e63-40f6-812f-0b080be21449?chat=panel&conversation=28eb6c74-3b02-44d5-b7bf-3f967820e7e9"
}- status is locked, with a message, when the project's free chat allowance is used up and the account has no credits.