curl --request POST \
--url https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"externalSourceId": "example-integrator:photo-page:page_123",
"photos": [
{
"externalSourceId": "<string>",
"imageAttachment": {
"key": "external-uploads/ckbuilder123456789012345678/photo.jpg",
"type": "attachment",
"regionId": "au1"
},
"fileName": "<string>",
"sequenceId": 123,
"imageUrl": "<string>",
"contentType": "image/jpeg",
"width": 123,
"height": 123,
"capturedAt": "2023-11-07T05:31:56Z"
}
],
"folderId": "<string>",
"sourceApp": "example-integrator",
"projectId": "<string>",
"folderName": "Site walkthrough - 2026-06-11"
}
'import requests
url = "https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert"
payload = {
"externalSourceId": "example-integrator:photo-page:page_123",
"photos": [
{
"externalSourceId": "<string>",
"imageAttachment": {
"key": "external-uploads/ckbuilder123456789012345678/photo.jpg",
"type": "attachment",
"regionId": "au1"
},
"fileName": "<string>",
"sequenceId": 123,
"imageUrl": "<string>",
"contentType": "image/jpeg",
"width": 123,
"height": 123,
"capturedAt": "2023-11-07T05:31:56Z"
}
],
"folderId": "<string>",
"sourceApp": "example-integrator",
"projectId": "<string>",
"folderName": "Site walkthrough - 2026-06-11"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
externalSourceId: 'example-integrator:photo-page:page_123',
photos: [
{
externalSourceId: '<string>',
imageAttachment: {
key: 'external-uploads/ckbuilder123456789012345678/photo.jpg',
type: 'attachment',
regionId: 'au1'
},
fileName: '<string>',
sequenceId: 123,
imageUrl: '<string>',
contentType: 'image/jpeg',
width: 123,
height: 123,
capturedAt: '2023-11-07T05:31:56Z'
}
],
folderId: '<string>',
sourceApp: 'example-integrator',
projectId: '<string>',
folderName: 'Site walkthrough - 2026-06-11'
})
};
fetch('https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'externalSourceId' => 'example-integrator:photo-page:page_123',
'photos' => [
[
'externalSourceId' => '<string>',
'imageAttachment' => [
'key' => 'external-uploads/ckbuilder123456789012345678/photo.jpg',
'type' => 'attachment',
'regionId' => 'au1'
],
'fileName' => '<string>',
'sequenceId' => 123,
'imageUrl' => '<string>',
'contentType' => 'image/jpeg',
'width' => 123,
'height' => 123,
'capturedAt' => '2023-11-07T05:31:56Z'
]
],
'folderId' => '<string>',
'sourceApp' => 'example-integrator',
'projectId' => '<string>',
'folderName' => 'Site walkthrough - 2026-06-11'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert"
payload := strings.NewReader("{\n \"externalSourceId\": \"example-integrator:photo-page:page_123\",\n \"photos\": [\n {\n \"externalSourceId\": \"<string>\",\n \"imageAttachment\": {\n \"key\": \"external-uploads/ckbuilder123456789012345678/photo.jpg\",\n \"type\": \"attachment\",\n \"regionId\": \"au1\"\n },\n \"fileName\": \"<string>\",\n \"sequenceId\": 123,\n \"imageUrl\": \"<string>\",\n \"contentType\": \"image/jpeg\",\n \"width\": 123,\n \"height\": 123,\n \"capturedAt\": \"2023-11-07T05:31:56Z\"\n }\n ],\n \"folderId\": \"<string>\",\n \"sourceApp\": \"example-integrator\",\n \"projectId\": \"<string>\",\n \"folderName\": \"Site walkthrough - 2026-06-11\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"externalSourceId\": \"example-integrator:photo-page:page_123\",\n \"photos\": [\n {\n \"externalSourceId\": \"<string>\",\n \"imageAttachment\": {\n \"key\": \"external-uploads/ckbuilder123456789012345678/photo.jpg\",\n \"type\": \"attachment\",\n \"regionId\": \"au1\"\n },\n \"fileName\": \"<string>\",\n \"sequenceId\": 123,\n \"imageUrl\": \"<string>\",\n \"contentType\": \"image/jpeg\",\n \"width\": 123,\n \"height\": 123,\n \"capturedAt\": \"2023-11-07T05:31:56Z\"\n }\n ],\n \"folderId\": \"<string>\",\n \"sourceApp\": \"example-integrator\",\n \"projectId\": \"<string>\",\n \"folderName\": \"Site walkthrough - 2026-06-11\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"externalSourceId\": \"example-integrator:photo-page:page_123\",\n \"photos\": [\n {\n \"externalSourceId\": \"<string>\",\n \"imageAttachment\": {\n \"key\": \"external-uploads/ckbuilder123456789012345678/photo.jpg\",\n \"type\": \"attachment\",\n \"regionId\": \"au1\"\n },\n \"fileName\": \"<string>\",\n \"sequenceId\": 123,\n \"imageUrl\": \"<string>\",\n \"contentType\": \"image/jpeg\",\n \"width\": 123,\n \"height\": 123,\n \"capturedAt\": \"2023-11-07T05:31:56Z\"\n }\n ],\n \"folderId\": \"<string>\",\n \"sourceApp\": \"example-integrator\",\n \"projectId\": \"<string>\",\n \"folderName\": \"Site walkthrough - 2026-06-11\"\n}"
response = http.request(request)
puts response.read_body{
"folderId": "<string>",
"createdAttachmentIds": [
"<string>"
],
"skippedExternalSourceIds": [
"<string>"
],
"failedPhotos": [
{}
],
"photos": [
{
"externalSourceId": "<string>",
"attachmentId": "<string>",
"status": "CREATED",
"error": {}
}
],
"status": "synced"
}Bulk upsert photos
Adds multiple photos to BuildPass for a photo report or project gallery folder. Returns a result for each photo and attachment IDs for successfully saved photos. Existing photos are reused to avoid duplicates.
curl --request POST \
--url https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"externalSourceId": "example-integrator:photo-page:page_123",
"photos": [
{
"externalSourceId": "<string>",
"imageAttachment": {
"key": "external-uploads/ckbuilder123456789012345678/photo.jpg",
"type": "attachment",
"regionId": "au1"
},
"fileName": "<string>",
"sequenceId": 123,
"imageUrl": "<string>",
"contentType": "image/jpeg",
"width": 123,
"height": 123,
"capturedAt": "2023-11-07T05:31:56Z"
}
],
"folderId": "<string>",
"sourceApp": "example-integrator",
"projectId": "<string>",
"folderName": "Site walkthrough - 2026-06-11"
}
'import requests
url = "https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert"
payload = {
"externalSourceId": "example-integrator:photo-page:page_123",
"photos": [
{
"externalSourceId": "<string>",
"imageAttachment": {
"key": "external-uploads/ckbuilder123456789012345678/photo.jpg",
"type": "attachment",
"regionId": "au1"
},
"fileName": "<string>",
"sequenceId": 123,
"imageUrl": "<string>",
"contentType": "image/jpeg",
"width": 123,
"height": 123,
"capturedAt": "2023-11-07T05:31:56Z"
}
],
"folderId": "<string>",
"sourceApp": "example-integrator",
"projectId": "<string>",
"folderName": "Site walkthrough - 2026-06-11"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
externalSourceId: 'example-integrator:photo-page:page_123',
photos: [
{
externalSourceId: '<string>',
imageAttachment: {
key: 'external-uploads/ckbuilder123456789012345678/photo.jpg',
type: 'attachment',
regionId: 'au1'
},
fileName: '<string>',
sequenceId: 123,
imageUrl: '<string>',
contentType: 'image/jpeg',
width: 123,
height: 123,
capturedAt: '2023-11-07T05:31:56Z'
}
],
folderId: '<string>',
sourceApp: 'example-integrator',
projectId: '<string>',
folderName: 'Site walkthrough - 2026-06-11'
})
};
fetch('https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'externalSourceId' => 'example-integrator:photo-page:page_123',
'photos' => [
[
'externalSourceId' => '<string>',
'imageAttachment' => [
'key' => 'external-uploads/ckbuilder123456789012345678/photo.jpg',
'type' => 'attachment',
'regionId' => 'au1'
],
'fileName' => '<string>',
'sequenceId' => 123,
'imageUrl' => '<string>',
'contentType' => 'image/jpeg',
'width' => 123,
'height' => 123,
'capturedAt' => '2023-11-07T05:31:56Z'
]
],
'folderId' => '<string>',
'sourceApp' => 'example-integrator',
'projectId' => '<string>',
'folderName' => 'Site walkthrough - 2026-06-11'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert"
payload := strings.NewReader("{\n \"externalSourceId\": \"example-integrator:photo-page:page_123\",\n \"photos\": [\n {\n \"externalSourceId\": \"<string>\",\n \"imageAttachment\": {\n \"key\": \"external-uploads/ckbuilder123456789012345678/photo.jpg\",\n \"type\": \"attachment\",\n \"regionId\": \"au1\"\n },\n \"fileName\": \"<string>\",\n \"sequenceId\": 123,\n \"imageUrl\": \"<string>\",\n \"contentType\": \"image/jpeg\",\n \"width\": 123,\n \"height\": 123,\n \"capturedAt\": \"2023-11-07T05:31:56Z\"\n }\n ],\n \"folderId\": \"<string>\",\n \"sourceApp\": \"example-integrator\",\n \"projectId\": \"<string>\",\n \"folderName\": \"Site walkthrough - 2026-06-11\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"externalSourceId\": \"example-integrator:photo-page:page_123\",\n \"photos\": [\n {\n \"externalSourceId\": \"<string>\",\n \"imageAttachment\": {\n \"key\": \"external-uploads/ckbuilder123456789012345678/photo.jpg\",\n \"type\": \"attachment\",\n \"regionId\": \"au1\"\n },\n \"fileName\": \"<string>\",\n \"sequenceId\": 123,\n \"imageUrl\": \"<string>\",\n \"contentType\": \"image/jpeg\",\n \"width\": 123,\n \"height\": 123,\n \"capturedAt\": \"2023-11-07T05:31:56Z\"\n }\n ],\n \"folderId\": \"<string>\",\n \"sourceApp\": \"example-integrator\",\n \"projectId\": \"<string>\",\n \"folderName\": \"Site walkthrough - 2026-06-11\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.buildpass.global/builders/{builderId}/photo-gallery/bulk-upsert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"externalSourceId\": \"example-integrator:photo-page:page_123\",\n \"photos\": [\n {\n \"externalSourceId\": \"<string>\",\n \"imageAttachment\": {\n \"key\": \"external-uploads/ckbuilder123456789012345678/photo.jpg\",\n \"type\": \"attachment\",\n \"regionId\": \"au1\"\n },\n \"fileName\": \"<string>\",\n \"sequenceId\": 123,\n \"imageUrl\": \"<string>\",\n \"contentType\": \"image/jpeg\",\n \"width\": 123,\n \"height\": 123,\n \"capturedAt\": \"2023-11-07T05:31:56Z\"\n }\n ],\n \"folderId\": \"<string>\",\n \"sourceApp\": \"example-integrator\",\n \"projectId\": \"<string>\",\n \"folderName\": \"Site walkthrough - 2026-06-11\"\n}"
response = http.request(request)
puts response.read_body{
"folderId": "<string>",
"createdAttachmentIds": [
"<string>"
],
"skippedExternalSourceIds": [
"<string>"
],
"failedPhotos": [
{}
],
"photos": [
{
"externalSourceId": "<string>",
"attachmentId": "<string>",
"status": "CREATED",
"error": {}
}
],
"status": "synced"
}write:photos. Accepts up to 100 photos per request.
Upload the files with POST /builders/{builderId}/attachments/bulk-upload, then pass each returned attachment reference as photos[].imageAttachment.
- Photo reports: omit
folderIdandfolderName. Use the returnedatt_attachment IDs in the photo report. - Gallery folders: provide
projectIdand afolderName, or reuse an existingfolderId.
CREATED, EXISTING or FAILED result. Keep external source IDs stable when retrying to avoid duplicates. URL imports require an HTTPS host approved by BuildPass.Authorizations
The access token received from the authorization server in the OAuth 2.0 flow.
- Token URL
- https://api.buildpass.global/oauth/token
Path Parameters
Body
A batch of up to 100 photos from the same external source.
Stable ID for this group of photos in your application. For photo reports, use the report’s sourceExternalId.
"example-integrator:photo-page:page_123"
1 - 100 elements- Option 1
- Option 2
Show child attributes
Show child attributes
Existing photo folder ID. Reuse it when adding photos to the same folder. Omit folderId and folderName for photo reports.
1 - 80"example-integrator"
Project that owns the photos. Required when using folderId or folderName; optional for photo reports.
1^proj_[a-z][a-z0-9]+$Name of a new project gallery folder. Requires projectId. Omit for photo reports.
"Site walkthrough - 2026-06-11"