Video upload workflow
A video upload follows a simple flow: create the upload session, PUT the file to the signed URL, and poll until processing completes.Create an upload session
- cURL
- Python
- Node.js
The response contains the content
id and a signed uploadUrl:
The POST create response uses the field name
status, while the status-polling GET response uses uploadStatus. Both hold the same upload_status values; the field-name difference is a known API quirk we plan to reconcile.Upload the video file
PUT the raw video bytes to the signed URL. This goes directly to storage — it does not pass through the ShortKit API.- cURL
- Python
- Node.js
waiting_for_upload to processing. When encoding completes, the status transitions to ready and the content becomes eligible for the feed. A caption track and spoken language detection are also generated automatically — these typically complete within a few minutes after the video reaches ready status. The detected language is stored as customMetadata.language (BCP 47 code, e.g. "en", "es", "ja").
iOS-recorded video
When the video was captured on an iOS device, include"origin": "ios_upload" in the upload request. iOS HEVC recordings frequently ship without explicit color metadata, and standard thumbnail extraction can produce wrong-color first frames under that condition. Marking the origin enables color-accurate thumbnail generation.
origin field, use PATCH /v1/content/:id with { "origin": "ios_upload" }. Thumbnail re-extraction is triggered automatically for eligible content.
If you render this content in a custom feed via the SDK, also set origin: .iosUpload (iOS) or 'ios_upload' (React Native) on the matching FeedInput.video so the client fetches the color-corrected thumbnail. See Custom feed input.
Poll for status
Check processing progress with the upload status endpoint:- cURL
- Python
- Node.js
ready, the response includes the playbackId and duration. The SDK uses the playback ID to resolve streaming and thumbnail URLs.
GET /v1/feed), subject to scheduling and editorial controls.
Use a webhook callback
As an alternative to polling, passcallbackUrl in the upload request to receive push notifications as the video moves through the pipeline.
- cURL
- Python
- Node.js
content.imported/status: "processing"— Sent when your file is received and processing begins. Contains theplaybackId.content.imported/status: "ready"— Sent when transcoding completes and all quality levels are available.content.import_failed/status: "error"— Sent if processing fails.
Carousel creation workflow
Carousels skip the processing pipeline entirely. They areready the moment you create them.
Create the carousel
- cURL
- Python
- Node.js
The response comes back with
status: "ready" immediately. No polling needed.
Upload images
Add images one at a time using multipart form data. Each carousel supports up to 10 images.- cURL
- Python
- Node.js
Reorder images
Pass all image IDs in the desired order. Each image’s position is set to its index in the array.Post-creation management
These operations apply to both videos and carousels.Update metadata
UsePATCH /v1/content/{contentId} to update any metadata field after creation. All fields are optional — only include the ones you want to change.
customMetadata uses shallow merge semantics: new keys are added, existing keys are overwritten, and keys set to null are removed. Other fields are replaced outright.
Add captions
Upload a VTT or SRT caption file for video content:- cURL
- Python
External captions are immediately
ready — no processing delay. They appear alongside any auto-generated tracks in feed responses and the SDK renders them automatically.
Add publication URLs
Attach external links to content (e.g., the source article, a product page). The first URL (position 0) is surfaced aspublisherUrl in the feed.
PUT /v1/content/{id}/publication-urls/{urlId}, PUT /v1/content/{id}/publication-urls/order, and DELETE /v1/content/{id}/publication-urls/{urlId}.
Archive content
Soft-delete content by sending a DELETE. The content is set toarchived status and removed from all feeds, but the record is preserved.