Skip to content

Downloading Input Files

Once input files are uploaded and finalized, you can download them again through the API.

It assumes you have a bundle with finalized input files and hold the read:bundle scope.


The download endpoint returns ready-to-use signed URLs. Download file bytes directly from CDN/S3 with no Authorization header on the GET, the same pattern used for scan file downloads.

sequenceDiagram
  participant Client as RCAPI client
  participant RCAPI as RCAPI
  participant CDN as CDN / S3

  Client->>RCAPI: GET input-files (page, limit)
  RCAPI-->>Client: items with signed urls + total
  loop for each item
    Client->>CDN: GET url
    CDN-->>Client: file bytes
  end

RCAPI signs the bundle’s input prefix once per request. Each item’s url is that signature with a wildcard replaced by the file’s storage path, so every URL in a single response shares the same expiry.

MethodPathScopePurpose
GET/v1/bundles/{bundleId}/input-filesread:bundleList signed download URLs for finalized input files
GET {api_url}/v1/bundles/{bundleId}/input-files?page=1&limit=20
Authorization: Bearer {access_token}
ParameterTypeDescription
pagenumber1-based page index (default 1)
limitnumberPage size (default 20, maximum 20)
sessionIduuidOptional. Limit results to files from one upload session

No sorting is offered. Files are returned in a stable storage order.

A paginated list ({ items, total }):

{
"items": [
{
"fileName": "scan.las",
"url": "https://cdn…/bundles/…/scan.las?X-Amz-…",
"sessionId": "6ebf0fe5-4428-4b26-a7e4-e3274980123b"
},
{
"fileName": "panorama/2024-07-scan-idx40.jpg",
"url": "https://cdn…/bundles/…/panorama/2024-07-scan-idx40.jpg?X-Amz-…",
"sessionId": "6ebf0fe5-4428-4b26-a7e4-e3274980123b"
}
],
"total": 28
}
FieldMeaning
fileNameThe input file’s name (the path substituted into the signed prefix)
urlSigned download URL, ready to GET without an auth header
sessionIdUpload session the file belongs to
totalTotal finalized input files across all pages

For each item, GET the url directly. No bearer token is required; the signature is embedded in the query string.

import requests
response = requests.get(item["url"])
response.raise_for_status()
with open(local_path, "wb") as handle:
handle.write(response.content)

All URLs in one response share a single signature expiry (about 24 hours, consistent with other signed links in the API). If a download returns 403 Forbidden, the URL has expired. Request a fresh page from the list endpoint and retry.

When total exceeds limit, page through the results:

import requests
API_URL = "https://<your-regional-api-url>"
TOKEN = "<access_token>"
BUNDLE_ID = "<bundleId>"
LIMIT = 20
headers = {"Authorization": f"Bearer {TOKEN}"}
base = f"{API_URL}/v1/bundles/{BUNDLE_ID}/input-files"
page = 1
while True:
listing = requests.get(
base, headers=headers, params={"page": page, "limit": LIMIT}
).json()
for item in listing["items"]:
local_name = item["fileName"].replace("/", "_")
data = requests.get(item["url"])
data.raise_for_status()
with open(local_name, "wb") as handle:
handle.write(data.content)
print(f"Downloaded {item['fileName']}")
if page * LIMIT >= listing["total"]:
break
page += 1
Use caseNotes
ArchivalCopy raw captures into your own storage after upload
ReprocessingDownload inputs locally, then upload to a new bundle
Audit / verificationConfirm which files landed on the bundle before processing
Integration testingRound-trip upload and download in CI pipelines

This endpoint returns input files only (what you uploaded). Processed outputs (HLODs, standardized point clouds, and so on) are exposed as bundle component signed links on GET /v1/site/{siteId}/bundles/{bundleId}. See Retrieving processed outputs.

StatusCause
403 ForbiddenMissing read:bundle scope or no read permission on the bundle
404 Not FoundUnknown bundleId

An empty items array with total: 0 means the bundle has no finalized input files yet. Complete an upload session first; see Uploading Data to a Data Bundle.