Skip to main content

upload() for cloud URIs

Provide full gs://, s3://, or hf://buckets/... URIs to import videos from cloud storage.
Cloud import examples
Cloud-specific parameter: 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.
1. Grant read access once. Obtain Nomadic’s Google service account identity:
Grant that identity read access on each bucket you import from, and repeat the grant for any new bucket. No service account key, 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.
2. Upload one directory or a list. Each path is the parent directory of one finalized recording, containing its Parquet files, calibration, and optional camera MP4 plus frame timestamps. Keep those files unchanged until copying finishes.
One call returns one job immediately after acceptance, with one reserved video ID per directory. 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:
Names default to directory basenames. To choose names or folders individually:
An item inherits the top-level folder unless it overrides it. 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.
Retry keeps the same job and video IDs and resumes the failed stage. Omit 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
For Cloudflare R2 and other S3-compatible providers, keep using 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 with gs:// 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=True is ignored for cloud multi-view uploads.
  • For multi-view import jobs, client.get_import_job_videos() returns front rows only and total is the requested set count.

get_import_job()

Fetch metadata for a cloud import job.
Required Parameters: Returns: Dict with job metadata fields such as:
  • job_id
  • source ("s3", "gcs", or "hf_bucket")
  • bucket
  • prefix
  • folder_id
  • folder_name
  • total
  • timestamps (created_at, completed_at, updated_at when 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 its integration_id into upload():
Prefer a fine-grained token if Hugging Face supports the required bucket access. If bucket-specific scoping is unavailable, use a dedicated token or account reserved for storage imports. Outside of integration creation, the SDK does not accept Hugging Face tokens. Use 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.
Required Parameters: Optional Parameters: Returns: Dict with:
  • import_job_id
  • total (requested count for this job; for multi-view jobs this is the requested set count)
  • limit
  • cursor
  • has_more
  • next_cursor
  • videos (list of {video_id, status, import_source_uri} entries for detailed polling; multi-view jobs return front rows only)
  • video_count
Cursor Notes:
  • cursor is the last video_id from the previous response’s next_cursor.
  • Start with cursor=None for the first page.
  • Stop paging when has_more is False.
  • Prefer cursor pagination for large jobs; offset is mainly a fallback/debug option.
  • Do not pass both cursor and offset in the same request.
  • For multi-view cloud imports, videos contains currently materialized IDs (best-effort); use total as the requested target count.
client.get_import_job_uploaded_video_ids() remains available as a deprecated alias of client.get_import_job_videos().

End-to-end cloud import example