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.
How it works
Section titled “How it works”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.
Endpoint
Section titled “Endpoint”| Method | Path | Scope | Purpose |
|---|---|---|---|
GET | /v1/bundles/{bundleId}/input-files | read:bundle | List signed download URLs for finalized input files |
List input file download URLs
Section titled “List input file download URLs”GET {api_url}/v1/bundles/{bundleId}/input-files?page=1&limit=20Authorization: Bearer {access_token}Query parameters
Section titled “Query parameters”| Parameter | Type | Description |
|---|---|---|
page | number | 1-based page index (default 1) |
limit | number | Page size (default 20, maximum 20) |
sessionId | uuid | Optional. Limit results to files from one upload session |
No sorting is offered. Files are returned in a stable storage order.
Response
Section titled “Response”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}| Field | Meaning |
|---|---|
fileName | The input file’s name (the path substituted into the signed prefix) |
url | Signed download URL, ready to GET without an auth header |
sessionId | Upload session the file belongs to |
total | Total finalized input files across all pages |
Download the bytes
Section titled “Download the bytes”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)Expired URLs
Section titled “Expired URLs”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.
Paginating large bundles
Section titled “Paginating large bundles”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 = 1while 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 += 1When to use this endpoint
Section titled “When to use this endpoint”| Use case | Notes |
|---|---|
| Archival | Copy raw captures into your own storage after upload |
| Reprocessing | Download inputs locally, then upload to a new bundle |
| Audit / verification | Confirm which files landed on the bundle before processing |
| Integration testing | Round-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.
Error cases
Section titled “Error cases”| Status | Cause |
|---|---|
403 Forbidden | Missing read:bundle scope or no read permission on the bundle |
404 Not Found | Unknown 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.