Skip to main content

Storage Profiles

A storage profile tells Native Frame where a project's media for a given surface should live. One API family — /program/api/v2/storage-profiles/{surface} — configures storage for every surface in one of two modes:

  • managed — Native Frame provisions and runs a per-project Backblaze B2 bucket for you. No credentials to manage; you get a built-in object listing, presigned downloads, and scoped download keys.
  • byo ("bring your own") — you point the surface at your own S3-compatible destination. You keep full control of the bucket; Native Frame writes to it.
Replaces per-feature storage config

The unified storage profile API supersedes the storage sections of the individual features. The Recording destination is now the archive surface, and snapshots and clips each carry their own destination rather than reusing the recording bucket.

Surfaces and modes

SurfacemanagedbyoNotes
snapshotsManaged unlocks the snapshot gallery + download keys.
archive❌ (422)A facade over the Recording config. Encoding (formats/fileType/path) still lives there; the profile owns the S3 destination.
assets✅ (publicUrlBase)Project-level default; a per-upload storageMode still overrides it.
clips❌ (409)Clips carry their own destination. Managed capture is on the roadmap.

This guide focuses on snapshots and managed storage; the same calls work for every surface.

Authentication

Everything below is backed by the Program Service HTTP API. Base path: /program/api/v2. Every call requires a Bearer JWT whose audience/role includes service-account; the project is taken from the token's projectID claim. See the Program API reference (the Storage section under Program).

Enable managed snapshot storage

PUT /program/api/v2/storage-profiles/{surface} — see Enable managed storage for a surface.

PUT /program/api/v2/storage-profiles/snapshots
Authorization: Bearer <jwt>
Content-Type: application/json

{ "mode": "managed" }

The first call lazily provisions a per-project B2 bucket and may take a few seconds; the profile comes back with status: "provisioning" and transitions to ready. The call is idempotent — repeating it returns the existing profile.

Check a profile's status

GET /program/api/v2/storage-profiles/{surface} — see Get the project's storage profile for a surface. Returns 200 with the profile, or 404 when the surface has no storage configured.

{
"projectId": "proj_123",
"surface": "snapshots",
"mode": "managed",
"status": "ready",
"provider": "backblaze",
"bucketName": "...",
"region": "...",
"endpoint": "...",
"createdAt": "2026-06-18T00:00:00Z",
"updatedAt": "2026-06-18T00:00:05Z"
}
note

A profile is a summary — it never includes access or secret keys.

Capturing snapshots

Snapshot capture is controlled per stream by a snapshot rule, independent of where the snapshots are stored:

Captured snapshots land in whatever storage the snapshots surface is configured to use.

List captured snapshots (managed)

GET /program/api/v2/streams/{id}/snapshots — see List a stream's captured snapshot objects.

GET /program/api/v2/streams/<streamId>/snapshots?limit=50
Authorization: Bearer <jwt>
{
"objects": [
{
"key": "snapshots/<streamId>/2026-06-18T00-00-00.jpg",
"sizeBytes": 84213,
"lastModified": "2026-06-18T00:00:00Z",
"downloadUrl": "https://...",
"expiresAt": "2026-06-18T00:10:00Z"
}
],
"nextCursor": "..."
}

Each downloadUrl is a time-limited presigned GET (valid for minutes) — render a gallery straight from these, with no storage login or raw credentials. Paginate with ?limit= and ?cursor= (pass back nextCursor).

Managed only

This list is for managed snapshot storage. If the surface is BYO, you access your own bucket directly and the list comes back empty.

Programmatic access with download keys

For tenants who want aws s3 ls/cp access to managed storage, mint a bucket-scoped, read-only key.

POST /program/api/v2/storage-profiles/{surface}/download-key — see Mint a scoped read-only download key.

{
"keyId": "...",
"applicationKey": "shown-once",
"bucketName": "...",
"s3Endpoint": "...",
"region": "...",
"expiresAt": "2026-07-18T00:00:00Z"
}
Copy the key now

applicationKey is returned once and is not retrievable later — capture it at creation time. The per-project master key is never exposed.

Revoke a key with DELETE /program/api/v2/storage-profiles/{surface}/download-key/{keyId} (204) — see Revoke a download key. Download keys are managed-only; requesting one on a BYO surface returns 422.

Bring your own storage

Point a surface at your own S3-compatible bucket with mode: "byo":

PUT /program/api/v2/storage-profiles/snapshots
Authorization: Bearer <jwt>
Content-Type: application/json

{
"mode": "byo",
"destination": {
"provider": "aws",
"bucket": "my-snapshots",
"region": "us-east-1",
"accessKey": "<access-key>",
"secretKey": "<secret-key>",
"pathTemplate": "snapshots/{streamId}/"
}
}
  • Secrets are stored in our secret manager and are never echoed back.
  • endpoint is optional only for Amazon S3 (the region derives it); every other provider requires it. See the Recording guide for the per-provider endpoint URLs and minimum IAM permissions.

Seed BYO storage from your recording config

If you already have a Recording (archive) destination configured, you can copy it onto another surface instead of re-entering credentials:

POST /program/api/v2/storage-profiles/{surface}/from-archive — see Configure a surface's BYO storage from the archiving config.

List all configured surfaces

GET /program/api/v2/storage-profiles — see List the project's storage profiles across all surfaces. Returns { "profiles": [...] }; unconfigured surfaces are omitted and credentials never appear.

Disable a surface's storage

DELETE /program/api/v2/storage-profiles/{surface} — see Disable / release a surface's storage. For managed surfaces this tears down the provisioned bucket.

Status codes

CodeMeaning
400Invalid mode, or a missing destination field (e.g. BYO assets without publicUrlBase).
404storage_profile_not_found — the surface has no configured storage.
409managed requested on a surface that doesn't provision it (clips today), or byo on a facade surface via the generic path.
422managed on archive, or a download key requested on a BYO surface.
503This deployment doesn't offer managed storage, or provisioning previously failed — retry or contact support.

Notes

  • A surface needs its own profile. Since the snapshot/clip → archive fallback was removed, a surface with no profile returns 422 when something tries to use it.
  • managed provisioning is lazy and idempotent — safe to call on every "enable" action.
  • The archive surface and the Recording config read and write the same destination; configure either one.