Skip to content

feat: add PDM API technical guide #330

Open
yoasyo25 wants to merge 2 commits intomainfrom
ya/DOCINT-1073/document-upload-technical-guide
Open

feat: add PDM API technical guide #330
yoasyo25 wants to merge 2 commits intomainfrom
ya/DOCINT-1073/document-upload-technical-guide

Conversation

@yoasyo25
Copy link
Contributor

@yoasyo25 yoasyo25 commented Feb 26, 2026

Jira Ticket:
🎫   DOCINT-1073

Adds a comprehensive step-by-step technical guide for API integrators building against the Procore Document Management V2 API.

Covers:

  • 8-step upload workflow (fetch requirements → create uploads → upload binary → update → retrieve event ID → submit as revision)
  • Full request/response examples
  • Error reference with HTTP status codes and resolution steps for Steps 4 and 8, including item-level failures in the failures array
  • End-to-end example with annotated JSON

@yoasyo25 yoasyo25 self-assigned this Feb 26, 2026
@yoasyo25 yoasyo25 force-pushed the ya/DOCINT-1073/document-upload-technical-guide branch 6 times, most recently from 3869b08 to b229b82 Compare March 5, 2026 22:52
@yoasyo25 yoasyo25 force-pushed the ya/DOCINT-1073/document-upload-technical-guide branch 2 times, most recently from d7a6ec3 to 92d3b77 Compare March 9, 2026 15:51
@yoasyo25 yoasyo25 changed the title wip feat: add PDM API technical guide Mar 9, 2026
@yoasyo25 yoasyo25 marked this pull request as ready for review March 9, 2026 15:54
Copilot AI review requested due to automatic review settings March 9, 2026 15:54
@yoasyo25 yoasyo25 requested a review from a team March 9, 2026 15:56
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new end-to-end technical guide intended to help integrators implement the full Procore Document Management (PDM) V2 upload + revision submission workflow, with scenario-based sequencing and error-handling guidance.

Changes:

  • Replaces the placeholder technical guide with a detailed 8-step upload/submission workflow, integration patterns, examples, and an error reference.
  • Adds a new “Constructing the Fields Array for API Requests” section to the metadata details reference to standardize how integrators format metadata payloads.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
document_management_integration/document_management_technical_guide.md Adds the comprehensive step-by-step PDM V2 upload/revision technical guide, including examples and error reference tables.
document_management_integration/document_management_metadata_details.md Adds guidance + a quick reference table for constructing fields arrays used in Document Uploads POST/PATCH payloads.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +529 to +535
"success": [
{
"id": "01JDXMPK0MTP0H41D4PYZ62R6R"
},
{
"id": "01JDXMPK0OTP0F32D2PWV40N4U"
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Step 6 partial-success example response, the success array includes an upload id (01JDXMPK0OTP0F32D2PWV40N4U) that does not appear in the preceding request example. This makes it unclear how to correlate request items to success/failed; please update the example IDs so they match the request payload.

Copilot uses AI. Check for mistakes.
Comment on lines +603 to +616
}
],
"label_source": "manual",
"label": "Type",
"description": "The document type"
},
{
"id": "01JDXMPK0BFD0670G3Z9JFB15F",
"name": "revision",
"type": "string",
"values": [{ "label": "Rev A" }],
"label_source": "manual",
"label": "Revision",
"description": "The document revision identifier"
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example show response uses "label_source": "manual", but elsewhere in this repo’s Document Management docs label_source values are uppercase (e.g., MANUAL, SYSTEM, ML). To stay consistent (and avoid implying a different enum), please update these example values/casing.

Copilot uses AI. Check for mistakes.
@yoasyo25 yoasyo25 force-pushed the ya/DOCINT-1073/document-upload-technical-guide branch from 92d3b77 to 9a2adf3 Compare March 9, 2026 16:14
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

**Step 1: Initialize Document Upload** - Create a Document Upload by providing filename and mime type. The system returns a unique upload ID.

**Step 2: Upload Binary File** - Use the [File Uploads API]({{ site.url }}{{ site.baseurl }}{% link tutorials/tutorial_uploads.md %}) to put the binary in storage. The Uploads API returns a file upload ID that identifies your file in storage.
**Step 2: Upload Binary File** - Use the Unified Uploads API *(documentation coming soon)* to put the binary in storage. The Uploads API returns a file upload ID that identifies your file in storage.
| 2 | `.../fields` | GET | Fetch available project fields and their IDs |
| 3 | `.../fields/{field_id_or_name}/values` | GET | Fetch field value IDs for dropdown list field types |
| 4 | `.../document_uploads` | POST | Initialize document upload records |
| 5 | `/rest/v1.1/projects/{project_id}/uploads` | POST, PUT, PATCH | Upload binary file to Procore storage using the **V2.1 Unified Uploads API** |
Comment on lines +567 to +568
| `uploads[].termination_reason` | string | Conditional | Required when `terminated_revision_status_id` is provided. Reason for terminating existing revision workflows (e.g., `"Superseded"`). See [Handling Workflow Conflicts](#handling-workflow-conflicts). |
| `uploads[].terminated_revision_status_id` | string | Conditional | Required when `termination_reason` is provided. The metadata value ID of the status to set on terminated revisions. |
"type": "lov_entry",
"field": { "id": "01JDXMPK09FD0892J5BDMJD37D", "name": "type", "label": "Type" },
"acceptable_values": [
{ "id": "01JDXMPK0HMV0N14A7S3C95V9N", "code": "DR", "label": "Drawing", "active": true }
Comment on lines +16 to +20
| [Bulk Update Document Upload](https://developers.procore.com/reference/rest/document-uploads?version=latest#bulk-update-document-uploads) | PATCH | /rest/v2.0/companies/{company_id}/projects/{project_id}/document_management/document_uploads | Updates one or more Document Uploads in the specified Project. |
| [List Project Fields](https://developers.procore.com/reference/rest/project-fields?version=latest) | GET | /rest/v2.0/companies/{company_id}/projects/{project_id}/document_management/fields | Returns the Fields for a Project. |
| [List Project Upload Requirements](https://developers.procore.com/reference/rest/project-upload-requirements?version=latest#list-project-upload-requirements) | GET | /rest/v2.0/companies/{company_id}/projects/{project_id}/document_management/upload_requirements | Returns a list of Upload Requirements for the Project. |
| [List Project Metadata Values](https://developers.procore.com/reference/rest/project-metadata-values?version=latest#list-project-metadata-values) | GET | /rest/v2.0/companies/{company_id}/projects/{project_id}/document_management/fields/{field_id_or_name}/values | Returns a list of Metadata Values for the specified field. |
| [Create Document Revisions](https://developers.procore.com/reference/rest/document-revisions?version=latest#create-document-revisions-v2) | POST | /rest/v2.0/companies/{company_id}/projects/{project_id}/document_management/document_revisions | Creates one or more document revisions from document uploads . |
| [Bulk Create Document Revisions](https://developers.procore.com/reference/rest/document-revisions?version=latest#create-document-revisions-v2) | POST | /rest/v2.0/companies/{company_id}/projects/{project_id}/document_management/document_revisions | Creates one or more document revisions from document uploads . |
@yoasyo25 yoasyo25 force-pushed the ya/DOCINT-1073/document-upload-technical-guide branch from 33d8406 to 4e3598b Compare March 17, 2026 13:29

Push your binary file to Procore's storage service. Because file storage and document metadata are handled by separate microservices, this step requires you to step outside the V2 Document Management endpoints and use the V2.1 Unified Uploads API. The purpose of this step is to get your file into Procore's storage and obtain the `upload_id` field from the response, which is referred to as `file_upload_id` in subsequent steps. This ID is the critical link between your binary file and the document upload record you created in Step 4.

For full request/response details, authentication requirements, and multipart uploads, see the Unified Uploads API *(documentation coming soon)*.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a placeholder curl or HTTP example showing the request shape (e.g., endpoint, headers, multipart body), even if it's marked as preliminary? A "coming soon" note without actionable guidance breaks the workflow for anyone following this end-to-end.

Comment on lines +658 to +661
| --- | --- | --- |
| 500 | `file_upload_id` is already linked to another upload; `upload_status: "COMPLETED"` was set with no file linked; or storage verification failed. | Use the `upload_id` from the response in the Binary File upload step. Always provide `file_upload_id` when setting `upload_status: "COMPLETED"`. For other server failures, retry after a short delay. |

> **Note on non-existent IDs:** If an id in update_params is a valid ULID but does not correspond to an existing upload, the API returns HTTP 207 but the entry is silently dropped — it will not appear in either the success or failed arrays and no error is raised. If all submitted IDs are non-existent, the response will be { "data": { "success": [], "failed": [] } }. Always cross-check the IDs in success against your request to detect any that were dropped.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to move this warning up to just after the response description, before the error tables? https://github.com/procore/documentation/pull/330/changes#diff-d43e5581f4ea3c3e5c7b5f50a85271ce3935ebcd68c9d01b67609fbbbf94c8c1R452

An integrator working on the happy path might not read this far down, and silently dropped IDs are the kind of thing that causes hard-to-debug production issues.

| Name | Action | Endpoint URI | Description |
| --- | --- | --- | --- |
| [Create Document Uploads](https://developers.procore.com/reference/rest/document-uploads?version=latest#bulk-create-document-uploads) | POST | /rest/v2.0/companies/{company_id}/projects/{project_id}/document_management/document_uploads | Creates one or more new Document Uploads in the specified Project. |
| [Bulk Create Document Uploads](https://developers.procore.com/reference/rest/document-uploads?version=latest#bulk-create-document-uploads) | POST | /rest/v2.0/companies/{company_id}/projects/{project_id}/document_management/document_uploads | Creates one or more new Document Uploads in the specified Project. |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file uses ?version=latest while the technical guide uses ?version=2.0 for the same endpoints. Would it be worth aligning on one version across both files?


| HTTP Status | Description | Resolution |
| --- | --- | --- |
| 500 | `file_upload_id` is already linked to another upload; `upload_status: "COMPLETED"` was set with no file linked; or storage verification failed. | Use the `upload_id` from the response in the Binary File upload step. Always provide `file_upload_id` when setting `upload_status: "COMPLETED"`. For other server failures, retry after a short delay. |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to split the 500 errors into separate rows, along with their fixes?


> **Webhooks:** A `Document Upload.Created` event fires for each upload created in this request. Subscribe to this event if you want to be notified when uploads are initialized. See [Introduction to Webhooks]({{ site.url }}{{ site.baseurl }}{% link plan_your_app/webhooks.md %}) and [Using the Webhooks API]({{ site.url }}{{ site.baseurl }}{% link plan_your_app/webhooks_api.md %}) for setup details.

> **Batch failures:** Validation errors cause the entire batch to fail with a 4xx status code and no uploads are created. This differs from the Update Document Uploads endpoint, which returns HTTP `207` and supports partial success. For error codes and resolution steps, see [Error Reference](#error-reference).
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a maximum batch size for the uploads array we could document here (and at the equivalent spots in Steps 6 and 8)? It would be easier for integrators to find the limit in the docs rather than through a failed request.


The show response includes `latest_event_id` for every upload. Save this value — you must pass it as `upload_latest_event_id` when submitting in Step 8. If you don't need ML-enriched metadata, grab this ID and proceed to step 8.

**2. Check async processing status**
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth adding some guidance around polling here? Maybe something like "poll every 5–10 seconds with exponential backoff with a timeout of 5 minutes"? We know how our systems behave and their approximate latencies (most of the time), so I think it would be helpful to pass this knowledge to integrators.


Two background processes may auto-populate fields after `upload_status` is set to `COMPLETED`:

- **ML** (PDF files only) — Procore analyzes file content and may populate fields such as Type, Description, Number, Revision, and Date Authored. Check `integrationStatuses.ML` — once it reaches `completed` or `error`, ML processing is finished. For details on which fields ML populates, precedence rules, and limitations, see [ML and Automated Features]({{ site.url }}{{ site.baseurl }}{% link document_management_integration/document_management_intro.md %}#machine-learning-ml-and-automated-features).
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to note that there is no webhook for ML events (like complete or error).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants