Working with File Attachments and Image Uploads
Overview
Many resources accessible through the Procore API accept file attachments or images. For new integrations, Procore recommends a direct upload flow:
- Create and complete an upload using the Uploads API.
- Associate the uploaded file with the target Procore resource.
This page focuses on that direct upload workflow so integrations can avoid request-body ambiguity across endpoints. The structure is similar to the Direct Drawing Uploads tutorial, but scoped to attachments use cases. The example workflow presented below covers:
- Create an upload and upload the file to storage
- Associate the uploaded file to
accident_logs - Associate the uploaded file to the
imagestool
Create an Upload and Upload the File
Start by creating an upload with the Direct File Uploads flow and then upload the file to the returned storage URL. Use this guide for complete request/response details:

Associate the Uploaded File to the Target Resource
After the upload is complete, associate the resulting upload identifier with the endpoint you are calling.
This page includes two concrete examples of this association step:
- Upload to
accident_logs - Upload to the
imagestool
Example A - Upload to accident_logs
Use the Accident Log direct-upload fields for attachment association with upload_ids.
Reference:
Example request
- Request Method:
POST - Request URL:
/rest/v1.0/projects/{project_id}/accident_logs - Request Body:
{
"accident_log": {
"time_hour": 10,
"time_minute": 15,
"comments": "Minor incident near loading zone",
"upload_ids": [
"01FZ8QATJYD0K7BZG2PP5GB4KN"
]
}
}

Example response
{
"id": 1047250,
"date": "2026-05-06",
"datetime": "2026-05-06T16:00:00Z",
"status": "approved",
"created_by_collaborator": false,
"position": 1,
"created_at": "2026-05-06T07:05:19Z",
"updated_at": "2026-05-06T07:05:19Z",
"deleted_at": null,
"created_by": {
"id": 14078128,
"login": "api.user@example.com",
"name": "API User"
},
"attachments": [
{
"id": 6181940361,
"name": "image.png",
"url": "https://example.com/files/{file_token}",
"filename": "image.png",
"content_type": "image/png",
"viewable_type": "image",
"share_url": "https://example.com/files/{file_token}",
"viewable_url": "https://example.com/viewable_documents/{document_id}"
}
],
"permissions": {
"can_update": true,
"can_delete": true
},
"custom_fields": {},
"related_items": [],
"location": null,
"comments": "Accident Log comments",
"involved_company": "Procore Technologies",
"involved_name": "Roger",
"time_hour": 10,
"time_minute": 15,
"vendor": null
}
Example B - Upload to images tool
For Create Image, use the upload.uuid flow from the Uploads API.
Reference:
Request
- Request Method:
POST - Request URL:
/rest/v1.0/images?project_id={project_id} - Request Body:
{
"upload": {
"source": "Image from API",
"uuid": "1QJ83Q56CVQR4X3C0JG7YV86F8",
"image_name": "image.png"
},
"image": {
"provider_type": "MarkupLayer",
"provider_id": 12,
"description": "This is a cool image",
"image_category_id": 2,
"location_id": 13,
"log_date": "2018-01-01",
"mt_location": [
"string"
],
"private": false,
"starred": true,
"trade_ids": [
1
]
}
}

Response Body
{
"id": 42,
"url": "https://example.com/files/{file_token}",
"size": 42,
"filename": "image.png",
"description": "This is a cool image",
"thumbnail_url": "https://example.com/files/{thumbnail_token}",
"taken_at": "2026-05-06T07:05:19Z",
"created_at": "2026-05-06T07:05:19Z",
"updated_at": "2026-05-06T07:05:19Z",
"location": {
"id": 15504,
"name": "1space>1 space",
"node_name": "1 space",
"parent_id": 788866,
"created_at": "2016-08-01T23:33:54Z",
"updated_at": "2016-08-01T23:33:54Z"
},
"image_category_name": "Progress Photos",
"image_category_id": 2,
"permanently_deleted": false,
"private": false,
"projection": "regular",
"starred": true,
"width": 42,
"height": 42,
"uploader": {
"id": 160586,
"login": "api.user@example.com",
"name": "API User"
},
"links": {
"self": "/rest/v1.0/images/9122752?image_category_id=186339&project_id=173074",
"update": "/rest/v1.0/images/9122752?image_category_id=186339&project_id=173074",
"delete": "/rest/v1.0/images/9122752?image_category_id=186339&project_id=173074",
"permanentlyDelete": "/rest/v1.0/images/9122752?image_category_id=186339&project_id=173074&permanent=true",
"retrieve": "/rest/v1.0/images/9122752/retrieve?project_id=173074"
},
"trades": [
{
"id": 999,
"name": "09 - acoustical panels",
"active": true,
"updated_at": "2016-08-01T23:33:54Z"
}
],
"comments_count": 42,
"daily_log_segment": {
"id": 123456,
"name": "Morning Shift",
"description": "Work performed during the morning shift",
"deleted_at": null,
"deleted": false
}
}
Possible responses include 201, 401, 403, and 422 depending on auth and validation.
Some endpoints still support image[data] in multipart/form-data, but uploads-first with upload.uuid is the recommended flow for new integrations.
Next Step
After you create or update the resource, use that tool’s resource endpoint(s) to confirm the association in the returned payload. Use the endpoint-specific reference docs for the resource you are integrating.
About multipart/form-data
Some resource endpoints still accept multipart/form-data, but this guide recommends using uploads-first association flows.
Multipart behavior is endpoint-specific and parameter names vary by endpoint:
accident_logs: useupload_idsin JSON requests, populated with values returned from Create Upload.images: use direct upload withupload.uuid.
Always check the endpoint reference before choosing multipart request-body upload versus upload-reference flow. This guide intentionally does not enumerate every tool-specific contract.