upload() for cloud URIs
Provide fullgs://, s3://, or hf://buckets/... URIs to import videos from cloud storage.
Cloud import examples
All other parameters (
folder, scope, etc.) are shared with local uploads — see the full parameter table.
Returns: {"import_job_id": "ij_xxx", "status": "importing"}
Ordinary video imports accept
.mp4 objects referenced by full gs://bucket/object.mp4, s3://bucket/object.mp4, or hf://buckets/namespace/name/object.mp4 URIs. Wildcard patterns are not supported—list each object explicitly. Zendar recording directories use the separate source_format option below. For Hugging Face buckets, when no integration_id is provided the backend first checks for a saved hf_bucket integration matching the bucket and otherwise falls back to public bucket access automatically.For S3-compatible providers such as Cloudflare R2, keep using
s3://bucket/object.mp4 URIs. The provider-specific endpoint belongs on the saved cloud integration, not in the import URI itself.Cloud import requests are acknowledged asynchronously. Even when a request later fails validation or authorization in background processing, the API still returns an
import_job_id; those failures surface as UPLOADING_FAILED rows in get_import_job_videos().Zendar recording directories (upcoming SDK release)
This feature requires the upcoming SDK release and account enablement by Nomadic.
Nomadic copies each recording directory into its own storage, converts it with the
existing Zendar converter, then ingests the resulting MCAP and sensor assets.
integration_id, or bucket registration
with Nomadic is required. The account is dedicated to your organization, so your
grants decide which buckets your uploads can read. Source buckets must be regional
us-central1.
wait_for_uploaded does not change this asynchronous behavior.
Each call accepts 1–1,000 directories in one bucket; ZIPs, individual Parquet files,
and recursive discovery beneath a collection of recordings are not supported.
Large batches. Submit up to 1,000 directories in one call; you don’t need to
pace or stagger uploads. Nomadic queues the recordings and processes them at the
rate its copy and ingestion capacity allows, so a large batch can take several
hours to finish. The SDK automatically generates an idempotency key for each
upload call and reuses it for automatic retries, so no key is needed in your code.
For more than 1,000 directories, submit one call per chunk:
folder=None keeps
an item unfiled. Use scope="org" for an organization folder. Folders group recordings
for analysis; uploading does not start analysis.
3. Check the job or individual videos.
status["summary"] counts completed, partial, failed, and in_progress
inputs. get_import_job suggests how long to wait before polling again in
poll_after_seconds (30 seconds for jobs over 100 inputs). Videos are returned in
video ID order, not submission order; match them to your inputs by name or
import_source_uri.
An individual import_status moves through queued, validating, copying,
converting, and ingesting, then ends as completed, partial, or failed.
While an input waits for capacity, progress["stage"] says why, for example
waiting_for_copy_slot. Waiting never fails an input.
The job remains processing while any input is unfinished, including when siblings
have failed. terminal=True means all inputs have finished. The existing uppercase
status field describes video upload readiness; import_status covers the full
recording and its required sensor assets.
Use next_cursor when has_more=True; start from cursor=None for each new status
refresh. A cursor marks a page position, not a stream of changes. Waiting returns
failed/partial outcomes too; a local timeout leaves server processing running.
video_ids to retry all eligible failures. Corrected source files require a new
upload. To resume monitoring after restarting your client, use the saved
import_job_id with get_import_job() or wait_for_import_job(). A new upload()
call creates a new import. If you need to safely repeat the submission itself
across restarts, supply the same optional idempotency_key and identical inputs,
names, folders, and scope; changing the request under that key returns HTTP 409.
Managing Cloud Integrations
Use this helper to manage reusable GCS/S3 credentials for cloud imports. See Cloud Storage Uploads for instructions on creating service-account keys and web UI setup.Cloud integrations helper
s3://bucket/key.mp4
URIs in client.upload(...). The custom endpoint stays on the saved integration
via endpoint_url; it does not go into the import URI.
Multi-view (cloud)
Cloud multi-view uploads use dict mappings withgs:// or s3:// URIs. front is required in every set.
- Multiple cloud multi-view sets submitted in one
upload([...])call produce one import job. wait_for_uploaded=Trueis ignored for cloud multi-view uploads.- For multi-view import jobs,
client.get_import_job_videos()returns front rows only andtotalis the requested set count.
get_import_job()
Fetch metadata for a cloud import job.
Returns: Dict with job metadata fields such as:
job_idsource("s3","gcs", or"hf_bucket")bucketprefixfolder_idfolder_nametotal- timestamps (
created_at,completed_at,updated_atwhen available)
Hugging Face integrations via the SDK
If you want to create and reuse a saved Hugging Face integration from the SDK, create it with the cloud integrations helper and then pass itsintegration_id into upload():
client.upload("hf://buckets/...") with an integration_id, or omit
integration_id and let the backend resolve a saved integration or public
access for that bucket.
For high-volume imports, treat
total + client.get_import_job_videos() as the readiness contract.get_import_job_videos()
Fetch paginated per-video upload statuses for a cloud import job. This endpoint is designed for large import jobs where returning all rows in one response would be expensive (for example, thousands to hundreds of thousands of videos). For jobs with more than ~1,000 videos, prefer cursor-based pagination (limit + cursor) instead of requesting everything at once.
Optional Parameters:
Returns: Dict with:
import_job_idtotal(requested count for this job; for multi-view jobs this is the requested set count)limitcursorhas_morenext_cursorvideos(list of{video_id, status, import_source_uri}entries for detailed polling; multi-view jobs return front rows only)video_count
cursoris the lastvideo_idfrom the previous response’snext_cursor.- Start with
cursor=Nonefor the first page. - Stop paging when
has_moreisFalse. - Prefer
cursorpagination for large jobs;offsetis mainly a fallback/debug option. - Do not pass both
cursorandoffsetin the same request. - For multi-view cloud imports,
videoscontains currently materialized IDs (best-effort); usetotalas the requested target count.
client.get_import_job_uploaded_video_ids() remains available as a deprecated alias of client.get_import_job_videos().