Skip to main content

Goal

Upload a video without exposing a permanent API key, with explicit size, format, origin and readiness handling.

Prerequisites

  • An authenticated backend endpoint controlled by your application
  • An Assets bucket with an appropriate MIME allowlist, maximum object size and visibility policy
  • An HTTPS browser origin; server token with assets:write and access to the selected space

Workflow

1
Create a short-lived capability on your backend for one authorized upload.
2
Return only its token to the authenticated browser.
3
Create a session, upload checksummed parts and complete it.
4
Save the asset ID, inspect readiness and perform any application-specific duration validation.

What the platform validates

  • Your backend chooses the bucket, user-specific key prefix or fixed key, allowed HTTPS origins, allowed MIME types, maximum bytes and expiry. The browser cannot receive or choose your permanent credentials.
  • Capability creation accepts expires_in up to one hour; use a shorter lifetime where practical. The file size and declared MIME type are checked when the session is created. Parts are byte-limited and verified against SHA-256. The assembled file must match the declared size and any whole-file checksum.
  • Configure the bucket MIME allowlist too: committed file content is sniffed and bucket object policy is checked. A browser accept filter or file.type alone is not content validation, and a capability MIME declaration is not a guarantee that a video can be decoded.
  • There is no max_duration_seconds field in the upload capability or session contract. Video processing probes actual media and rejects unsupported media or processing duration outside its bounds; the current processor limit is one hour. That is not a configurable customer upload-duration policy and does not reject the upload before storage.
  • For a hard application limit such as 60 seconds, keep uploads private and unavailable in your application until your backend has validated the actual video duration. A browser metadata check can provide early feedback but cannot enforce that security rule.

Backend: issue one capability

After authenticating your application user and applying your own quota/rate limits, make this request on your server. Replace the example bucket and origin with real values; choose a prefix derived from the authenticated user, not arbitrary request input. The 100 MiB limit is an example policy and must fit your platform/account limits. The success response contains data.token and data.capability.expires_at. Return only the short-lived token and expiry to the browser. Authorize the host endpoint with your own session and CSRF protections as applicable.

Browser: upload with the capability

This minimal sequential example shows the wire protocol without a package dependency. Call uploadVideo(file, token, serverApprovedKey) after your backend returns a capability. Browsers set Origin automatically; do not add an Origin header in fetch. The widget routes are rooted at /assets/widget, not /api/v1/assets/widget. For a full progress/resume UI, use the embeddable upload widget. This small example deliberately omits retries and reload persistence; use the recovery endpoints below if implementing those yourself.

Completion, interruptions and visibility

Completion returns data containing the asset record and revokes the capability. Store asset.id in your application database. Upload completion does not mean the file has passed scanning, native video processing or review. Poll GET /api/v1/assets/{assetID} using your backend credentials and continue with the native video guide before editing or playback. GET /assets/widget/sessions/current returns the bound session and received parts while its capability remains valid. Resume only missing parts of the same file. DELETE /assets/widget/sessions/current cancels the upload. Obtain a fresh capability when the old one expires; a capability cannot authorize a second session. If the completion response is lost, have your backend reconcile the session with its server credentials before starting another upload. Do not assume a retry with the now-revoked browser token means the file was never stored. Capability sessions do not expose a browser-controlled visibility field. Configure the bucket default for the desired policy; use private for untrusted customer uploads. Download URLs are separate from upload/session tokens.

Expected result

Upload a video without exposing a permanent API key, with explicit size, format, origin and readiness handling.

Common failures

  • 401/403: check capability expiry, exact HTTPS Origin, session binding and current account access.
  • MIME or size rejected: inspect both capability limits and bucket/content policy. Changing the browser accept attribute does not change server policy.
  • Checksum errors require recomputing SHA-256 over the exact part bytes.
  • Do not claim a video meets your custom duration limit based only on successful upload.

Direct browser uploads

Upload browser files directly with short-lived sessions, per-part checksums, progress callbacks, retries, resume, and cancellation.

Embeddable Assets upload widget

Install @stackshift-cloud/assets-widget for React or vanilla JavaScript with constrained backend-issued capabilities, resumable chunks, camera and URL input, cropping, previews, progress, retry, and cancellation.

Trim videos, create JPG posters and download MP4s

Copyable REST recipes for start/end trimming with audio, timestamp JPEG posters, job polling and signed download URLs for external AI services.

Import generated videos from an external URL

Copy an AI-generated MP4 into permanent Assets storage using a constrained remote-URL capability, then track readiness and deliver it safely.