Ingesting media
Get source video into open-videocore: from a URL, direct upload, presigned/multipart upload, or an object storage watch-folder.
Every asset starts as a record, then gets its source media attached to it one of four ways. Pick the one that matches where your video already lives.
1. Create the asset record
An asset always starts as a record you create explicitly, or one created for you by the ingest-from-URL shortcut below.
curl -X POST https://<your-instance>/api/v1/assets \
-H "Content-Type: application/json" \
-d '{"title": "Keynote recording", "description": "Opening keynote, main stage"}'See POST /api/v1/assets/ — full field list in the Assets reference.
2. Ingest from a public URL
If the source file is already reachable over HTTP(S), skip the manual create step — this creates the asset and starts the download in one call:
curl -X POST https://<your-instance>/api/v1/assets/ingest-url \
-H "Content-Type: application/json" \
-d '{"sourceUrl": "https://example.com/video.mp4", "title": "Keynote recording"}'This returns a Job of type ingest-url. Poll GET /api/v1/jobs/{id} until status is done; the job's assetId is the asset to work with next.
3. Direct upload (small files)
For files you already have locally and that are small enough to send in one request:
curl -X PUT https://<your-instance>/api/v1/assets/<id>/upload \
-H "Content-Type: video/mp4" \
--data-binary @video.mp44. Presigned upload (browser / large single-part)
To upload directly to object storage from a browser or client without proxying bytes through the API, get a presigned URL first, upload to it, then tell the API the upload finished:
curl -X POST https://<your-instance>/api/v1/assets/<id>/upload-url
# -> { "url": "https://...", ... } — PUT your file bytes to that URL, then:
curl -X POST https://<your-instance>/api/v1/assets/<id>/upload-complete5. Multipart upload (large files)
For files too large for a single PUT, initiate a multipart upload, request a presigned URL per part, upload each part directly to storage, then complete:
POST /api/v1/assets/{id}/multipart/initiateGET /api/v1/assets/{id}/multipart/{uploadId}/part-url— once per partPOST /api/v1/assets/{id}/multipart/{uploadId}/complete- If something goes wrong:
DELETE /api/v1/assets/{id}/multipart/{uploadId}— abort
6. Watch-folder ingest
Point open-videocore at an object storage bucket and it will pick up new files dropped straight into that bucket (via mc, rclone, or another system) automatically, without any per-file API call:
curl -X POST https://<your-instance>/api/v1/storage/buckets/<bucket>/watch-folder/toggle \
-H "Content-Type: application/json" \
-d '{"enabled": true}'Prerequisites
Watch-folder ingest is only wired up when the deployment is pointed at a single, directly-reachable object-storage endpoint. Two things must both be configured on the API process:
- A global object-storage endpoint via the
MINIO_URLenvironment variable (withMINIO_ACCESS_KEY/MINIO_SECRET_KEY). Without this the watch-folder service is never started — the API falls back to the per-request upload and URL-pull routes only. - The opt-in flag
WATCH_FOLDER_ENABLED=true. The service is disabled by default even when object storage is configured.
Optionally, tune the polling fallback cadence with WATCH_FOLDER_POLL_INTERVAL_SECONDS (default 30); it is used when the storage backend does not expose bucket-change notifications.
Verify it is active
Confirm the watch-folder is configured and running before you rely on it:
curl https://<your-instance>/api/v1/admin/watch-folder/statusA response of {"enabled": true, "running": true, ...} means the service is configured and watching. "enabled": false means the prerequisites above are not met on this deployment (no global object-storage endpoint, or WATCH_FOLDER_ENABLED is not set) and watch-folder ingest is unavailable there. See the Admin reference for the poller's start/stop controls and the Storage reference for per-bucket listing and toggling.
status moving from uploading to processing to ready (or failed). Watch that field, or an asset.ready / asset.failed webhook, rather than polling the job directly once the source file has landed.