Model APIs

File access controls

On this page
  1. How access works
  2. Library scope
  3. Share links
    1. Create a link
    2. List active links
    3. Resolve the media
    4. Revoke a link
    5. Preview metadata and renders

Library access follows the caller's personal or organization scope. To give someone access without an account, create a share link with a deadline, keep the returned URL, and revoke the link when it is no longer needed.

There is no per-file ACL on the storage object itself; access is the Library scope plus share links.

How access works #

Request and caller Result Why
GET /assets/{id} for your live asset in personal scope 200 with an asset and signed URL The asset is in your Library
GET /assets/{id} for a teammate's live asset in your active organization 200 with an asset and signed URL Organization assets belong to the shared Library; user_id still identifies the creator
Share management for an asset outside the caller's Library scope 404 The target must be visible in the current scope
Create a share link as a viewer or billing role 403 Read-only role Reading the Library does not grant sharing authority
Create a share link as a member for another teammate's asset 403 Forbidden Members may share only assets they created; owners/admins may share any
Public resolver for an active share link 302 to temporary media No account or bearer token is required
Public resolver for a revoked/expired link or trashed/deleted media 410 The link no longer provides access
Public resolver for an unknown token 404 No matching link exists
Public resolver over its per-IP limit 429, Retry-After: 60 Wait before trying again

The 302 is the resolver response, not the media body. Follow its Location to fetch the bytes.

Library scope #

Personal assets belong to your personal Library. In organization context, teammates can read the shared Library, while the asset's user_id continues to name its creator. Choose the active context with PUT /me/active-organization; organization API keys stay bound to their organization. See Teams and organizations for switching context and roles.

Role or scope Create a share link Revoke a share link
Personal asset owner Own ready, untrashed assets Links on own assets
Organization owner/admin Any ready, untrashed asset in that organization Links on any asset in that organization
Organization member Assets they created Links they created or links on assets they can change
Organization viewer/billing Refused with 403 Read-only role Refused with 403 Read-only role
A durable share link and its temporary media URL Create a share link for an asset or render. Save the returned share URL. A visitor resolves the token without an account and receives a 302 redirect to media signed for about 15 minutes. Revoking the link makes future resolutions return 410 Gone. Owner creates access Visitor opens the link Create share POST /assets/{id}/share or /renders/{id}/share Save share URL returned once 30 days by default Public resolver GET /share/{token} no account needed Media signed URL about 15 minutes 302 Revoke share token or link id 410 Gone future resolutions revoked or expired Keep the share URL. Refresh the media URL on each visit.
Create a share link, resolve it to a short-lived media URL, and revoke it to return 410
Property Value
Endpoint POST /assets/{id}/share
Default lifetime 30 days
Custom lifetime expires_in_days, an integer from 1 through 365
Success 201 with a ShareLink
Returned once token and url; later listings cannot recover either
Field Type Required Description
expires_in_days integer No Lifetime of the link in days from now. Defaults to 30. Ignored when never_expires is true.
never_expires boolean No A link with no end date. Refused (400, code share_expiry_exceeds_organization_limit) when the organization sets a maximum lifetime.
password string No Viewers must enter this password before the media is served. Stored only as an argon2id hash; never returned.
view_only boolean No Turn downloads off for this link. The share page offers no Download and the resolver refuses download=true. A viewer who can play media can still capture it, so treat this as a deterrent, not copy protection.

Set ASSET_ID to a ready asset you are allowed to share. These request examples use a seven-day lifetime. The CLI currently has no share command; its tab uses curl with the same NOLGIA_TOKEN credential.

shellCreate share link example
curl --fail-with-body -sS "https://api.nolgia.ai/v1/assets/$ASSET_ID/share" \
  -H "Authorization: Bearer $NOLGIA_TOKEN" \
  -H "Content-Type: application/json" -d '{"expires_in_days":7}'
shellShare through the HTTP API example
curl --fail-with-body -sS "https://api.nolgia.ai/v1/assets/$ASSET_ID/share" \
  -H "Authorization: Bearer $NOLGIA_TOKEN" \
  -H "Content-Type: application/json" -d '{"expires_in_days":7}'
TypeScriptCreate share link example
import { createNolgiaClient } from "@nolgia/sdk";

const nolgia = createNolgiaClient(process.env.NOLGIA_TOKEN!);
const { data: link, error } = await nolgia.POST("/assets/{id}/share", {
  params: { path: { id: process.env.ASSET_ID! } },
  body: { expires_in_days: 7 },
});
if (error) throw new Error(`${error.title}: ${error.detail ?? ""}`);
console.log(link.id, link.url);
PythonCreate share link example
import os
from uuid import UUID
from nolgia import AuthenticatedClient
from nolgia.api.sharing import create_asset_share_link
from nolgia.models import CreateShareLinkRequest, ShareLink

client = AuthenticatedClient(base_url="https://api.nolgia.ai/v1", token=os.environ["NOLGIA_TOKEN"])
link = create_asset_share_link.sync(
    UUID(os.environ["ASSET_ID"]), client=client,
    body=CreateShareLinkRequest(expires_in_days=7),
)
if not isinstance(link, ShareLink):
    raise SystemExit(f"refused: {link}")
print(link.id, link.url)
RustCreate share link example
use nolgia_client::ClientBuilder;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = ClientBuilder::new("https://api.nolgia.ai/v1")
        .bearer_token(std::env::var("NOLGIA_TOKEN")?)
        .build()?;
    let id = std::env::var("ASSET_ID")?.parse::<uuid::Uuid>()?;
    let link = client.create_asset_share_link().id(id)
        .body_map(|b| b.expires_in_days(7_u64))
        .send().await?.into_inner();
    println!("{} {:?}", link.id, link.url);
    Ok(())
}

This is the production create response from share-create.json; the token and the URL's token are redacted. The SDK snippets are examples, not separate live captures.

JSON201 — share-create.json
{
  "access_count": 0,
  "created_at": "2026-09-21T03:33:52.874514Z",
  "created_by": "dad27b53-a85b-4e3d-8fd6-b152c803a27c",
  "expires_at": "2026-09-28T03:33:52.873377Z",
  "id": "26d786f5-437c-4da4-9f04-60342191299b",
  "kind": "asset",
  "target_id": "f7bc037c-d7d7-434a-8843-26675574de0d",
  "token": "…",
  "token_prefix": "EJIkUdv1",
  "url": "https://nolgia.ai/s/…"
}
Field Type Required Description
id string Yes
kind ShareLinkKind Yes
target_id string Yes The shared asset's id, or the shared render's id.
token string No The share token (base64url, 128 bits of entropy). Create response only.
token_prefix string Yes The first characters of the token, for recognising a link in a listing.
url string No The public share URL to hand out (the nolgia.ai share page). Create response only.
expires_at string No When the link stops resolving. Absent for a link that never expires.
has_password boolean No Viewers must enter a password.
view_only boolean No Downloads are turned off for this link.
created_at string Yes
created_by string Yes The user who created the link.
access_count integer Yes Successful public resolutions so far.
last_accessed_at string No When the link was last resolved. Absent until the first visit.
revoked_at string No Set once the link has been revoked. Listings only return unrevoked links.
Property Value
Endpoint GET /assets/{id}/share
Order Newest first
Included Unrevoked, unexpired links
Omitted Tokens and URLs
Management handle Use each link's id to revoke it
shellList share links example
curl --fail-with-body -sS "https://api.nolgia.ai/v1/assets/$ASSET_ID/share" \
  -H "Authorization: Bearer $NOLGIA_TOKEN"
JSON200 — share-list.json
{
  "links": [
    {
      "access_count": 1,
      "created_at": "2026-09-21T03:33:52.874514Z",
      "created_by": "dad27b53-a85b-4e3d-8fd6-b152c803a27c",
      "expires_at": "2026-09-28T03:33:52.873377Z",
      "id": "26d786f5-437c-4da4-9f04-60342191299b",
      "kind": "asset",
      "last_accessed_at": "2026-09-21T03:33:53.01188Z",
      "target_id": "f7bc037c-d7d7-434a-8843-26675574de0d",
      "token_prefix": "EJIkUdv1"
    }
  ]
}
Response field Meaning
links Active links, each using the ShareLink fields above without token or url
links[].id, links[].token_prefix Revoke handle and short recognition aid
links[].kind, links[].target_id Whether the target is an asset/render and which target it is
links[].created_by, links[].created_at, links[].expires_at Creator, creation time and share deadline
links[].access_count, links[].last_accessed_at Successful public resolutions and the latest one; metadata reads do not increment the count

Resolve the media #

Property Value
Endpoint GET /share/{token}; no authentication
Success 302 with a fresh signed media URL in Location
Media URL lifetime About 15 minutes
Caching Cache-Control: no-store on the redirect
Download Add ?download=true for a Content-Disposition: attachment media URL

Set SHARE_TOKEN to the token returned at creation. This command shows the resolver response without following it; add -L to fetch the media.

shellInspect public resolver example
curl -sS -D - -o /dev/null "https://api.nolgia.ai/v1/share/$SHARE_TOKEN"

These are the real response headers from share-resolve.headers; location is truncated.

HTTP302 — share-resolve.headers
HTTP/2 302
access-control-allow-headers: Authorization, Content-Type, X-Request-Id, If-Match, Idempotency-Key
access-control-allow-methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
access-control-allow-origin: *
cache-control: no-store
content-type: text/html; charset=utf-8
location: https://storage.googleapis.com/nolgia-generations-prod/dad27b53-a85b-4e…
x-cloud-trace-context: 978e41fdddedef4cd8db4b39631ad0cd
date: Mon, 21 Sep 2026 03:33:53 GMT
server: Google Frontend
content-length: 941
via: 1.1 google
alt-svc: h3=":443"; ma=2592000
Response field Meaning
HTTP status 302 Follow the redirect; this response is not the media
location Short-lived download URL, refreshed on each resolution
cache-control no-store; do not cache the resolver response
content-type, content-length The redirect's HTML body, not the media's MIME type or size
date, trace and infrastructure headers Response metadata, not share-link settings
access-control-* Cross-origin response headers

A valid share URL can outlast many media URLs. Keep the share URL and resolve it when needed; do not persist the Location as a replacement for the share link.

Property Value
Endpoint DELETE /assets/{id}/share/{token}
{token} accepts The original token or the link id from the listing
Success 204, no response body; already revoked is also 204
Wrong target 404 if the link does not exist or belongs to another asset
Next public resolution 410 Gone

The path parameter is named token, but the captured revoke used the link id 26d786f5-437c-4da4-9f04-60342191299b and returned 204. Use your own listing's id as SHARE_LINK_ID.

shellRevoke by link id example
curl --fail-with-body -sS -X DELETE \
  "https://api.nolgia.ai/v1/assets/$ASSET_ID/share/$SHARE_LINK_ID" \
  -H "Authorization: Bearer $NOLGIA_TOKEN"
HTTPRevoke result
HTTP/2 204

There is no JSON body. The same public resolver request now returns the real problem captured in share-gone.json:

shellResolve a revoked link example
curl -sS "https://api.nolgia.ai/v1/share/$SHARE_TOKEN"
JSON410 — share-gone.json
{
  "detail": "this share link has been revoked",
  "request_id": "localhost/7bnUUXx7b2-007297",
  "status": 410,
  "title": "Gone",
  "type": "about:blank"
}
Response field Meaning
status, title 410 Gone: the link no longer resolves
detail This capture identifies revocation; expired links and deleted media give their own reason
request_id Correlation id to include when asking for help
type Problem type; about:blank here

Revocation stops future resolutions. A previously issued signed media URL has its own short expiry; revoking the share does not change that URL's signature.

Preview metadata and renders #

GET /share/{token}/meta returns the title, modality, media URL and expiry for a preview page or embed, with an optional description, thumbnail, duration and size. It has the same unknown/revoked/rate-limit behavior as the resolver, but does not increment the link's access count.

Field Type Required Description
kind ShareLinkKind Yes
title string Yes The asset's display name (or a trimmed prompt), or the composition's name for a render.
description string No A short description when one is known (the generation prompt, or the composition's description).
model string No Catalog id of the model that generated the shared media (render it with the catalog's display name, never raw).…
preset ShareLinkPreset No
modality Modality Yes
mime_type string No
media_url string Yes Freshly signed short-lived URL of the media itself. Play or embed it now; never store it.
media_expires_at string Yes When media_url (and thumbnail_url) stop working. Fetch the metadata again for a new one.
thumbnail_url string No Freshly signed short-lived poster image, when the media has one.
duration_seconds number No Media duration for video and audio, when known.
size_bytes integer No
expires_at string No When the share link itself stops resolving. Absent for a link that never expires.
view_only boolean No Downloads are turned off for this link; offer no Download.
created_at string Yes
creator_insider InsiderBadge No Present only when the link's owner is an active NOLGIA Insider (who chose a public profile) and the link is a personal one: their badge, linking to nolgia.ai/@handle. Absent for everyone else.

Renders use the same create, list and revoke pattern under /renders/{id}/share and /renders/{id}/share/{token}. Their visibility follows the composition's Library scope. Both kinds resolve through the same public /share/{token} and /share/{token}/meta routes.

Method Path What it does
GET /assets/{id}/share List the active share links on an asset.
POST /assets/{id}/share Create a durable public share link for an asset.
DELETE /assets/{id}/share/{token} Revoke a share link on an asset.
GET /renders/{id}/share List the active share links on a render.
POST /renders/{id}/share Create a durable public share link for a finished render.
DELETE /renders/{id}/share/{token} Revoke a share link on a render.
GET /me/share-links List every active share link in the caller's library, newest first.
GET /me/share-links/policy The share-link rules that apply in the caller's current space.
GET /share/{token} Public resolver (no authentication) that redirects to the shared media.
GET /share/{token}/meta Public metadata (no authentication) for a share link's preview page.
POST /share/{token}/unlock Trade a share link's password for a short-lived viewing grant (no authentication).