Model APIs

Storage and data retention

On this page
  1. Generated media
  2. Request payloads
  3. Trash and deletion
    1. Move an asset to trash and restore it
  4. Bring your own storage
  5. Summary

Keep asset ids in your application and fetch download URLs when you need them. A signed URL's expiry controls access to the bytes; it is separate from when the asset is deleted.

Generated media #

Uploaded and generated assets are stored in Google Cloud Storage (GCS). signed_url is stable for about an hour: reads within the same clock hour return the same signed URL so the media can be cached across refreshes. Each asset read signs for the current window, with at least one hour of validity remaining; expires_at reports the real expiry.

Property Value
Durable identifier Asset.id
Download location signed_url
Exact deadline expires_at
Refresh Read GET /assets/{id} again
Thumbnail thumbnail_url for an image downscale or video poster; null when absent
Attachment download GET /assets/{id}?disposition=attachment
Field Type Required Description
id string Yes
signed_url string Yes Time-limited GCS signed URL for download.…
expires_at string Yes Expiry of signed_url.
mime_type string No
size_bytes integer, nullable No
width integer, nullable No
height integer, nullable No
duration_seconds number, nullable No Media duration in seconds for video/audio assets.…
has_audio boolean, nullable No Whether the asset's media carries an audio stream.…
thumbnail_url string, nullable No Time-limited signed URL for a server-generated thumbnail (image downscale or video poster frame).…
status AssetStatus No
deleted_at string, nullable No When the asset was moved to the trash (soft-deleted). Omitted for live assets; only trash listings (GET /assets?trashed=true) return trashed assets. Trashed assets are purged permanently 30 days after this timestamp.
created_at string Yes

Optional media metadata can lag behind the bytes. Uploaded or older videos may have no duration, audio verdict or poster until the asynchronous media sweep has inspected them. A missing thumbnail_url is not a failed asset.

Request payloads #

The asset stores the prompt. For images, prompt preserves the customer's words; enhanced_prompt contains the composed prompt that actually ran when it differs. For video and audio, prompt is the dispatched prompt and enhanced_prompt is absent or null. Uploaded assets may have no prompt.

There is no switch to stop storing prompts and no per-request expiry header.

Field What is retained
prompt Customer image prompt, or dispatched video/audio prompt
enhanced_prompt Composed image prompt, only when different from prompt
created_at When the asset was created
deleted_at When it entered trash; omitted on live assets

Trash and deletion #

The lifecycle is live → trash → permanent deletion. DELETE /assets/{id} moves an asset to trash and keeps its stored bytes for recovery. The API purges trashed assets 30 days after deleted_at, or you can call the permanent-delete endpoint earlier.

Action Endpoint Result
Move to trash DELETE /assets/{id} 204; hidden from default reads and listings
List trash GET /assets?trashed=true Only soft-deleted assets
Restore POST /assets/{id}/restore 200 asset with a current signed URL; already-live assets are an idempotent no-op
Delete forever DELETE /assets/{id}/permanent 204; works on both live and trashed assets

The trash filter is trashed=true. The separate status parameter chooses uploading or ready; it does not select trash. Deleting an already-trashed asset returns 404.

Move an asset to trash and restore it #

Property Value
Input ASSET_ID, an asset in your current Library scope
Delete response 204, no response body
Restore response 200, an Asset
Recovery window Restore before the 30-day purge or a permanent deletion

These examples perform both operations in order. The CLI supports assets delete; it has no restore command, so its tab uses the HTTP restore call. The Rust example configures an empty-body Content-Length for the generated bodyless POST.

shellTrash and restore example
curl --fail-with-body -sS -X DELETE "https://api.nolgia.ai/v1/assets/$ASSET_ID" \
  -H "Authorization: Bearer $NOLGIA_TOKEN"
curl --fail-with-body -sS -X POST "https://api.nolgia.ai/v1/assets/$ASSET_ID/restore" \
  -H "Authorization: Bearer $NOLGIA_TOKEN" --data ''
shellTrash and HTTP restore example
nolgia assets delete "$ASSET_ID"
curl --fail-with-body -sS -X POST "https://api.nolgia.ai/v1/assets/$ASSET_ID/restore" \
  -H "Authorization: Bearer $NOLGIA_TOKEN" --data ''
TypeScriptTrash and restore example
import { createNolgiaClient } from "@nolgia/sdk";

const nolgia = createNolgiaClient(process.env.NOLGIA_TOKEN!);
const params = { path: { id: process.env.ASSET_ID! } };
const { error: deleteError } = await nolgia.DELETE("/assets/{id}", { params });
if (deleteError) throw new Error(`${deleteError.title}: ${deleteError.detail ?? ""}`);
const { data: asset, error } = await nolgia.POST("/assets/{id}/restore", { params });
if (error) throw new Error(`${error.title}: ${error.detail ?? ""}`);
console.log(asset.id, asset.signed_url);
PythonTrash and restore example
import os
from http import HTTPStatus
from uuid import UUID
from nolgia import AuthenticatedClient
from nolgia.api.assets import delete_asset, restore_asset
from nolgia.models import Asset

client = AuthenticatedClient(base_url="https://api.nolgia.ai/v1", token=os.environ["NOLGIA_TOKEN"])
asset_id = UUID(os.environ["ASSET_ID"])
deleted = delete_asset.sync_detailed(asset_id, client=client)
if deleted.status_code != HTTPStatus.NO_CONTENT:
    raise SystemExit(f"refused: {deleted.parsed}")
asset = restore_asset.sync(asset_id, client=client)
if not isinstance(asset, Asset):
    raise SystemExit(f"refused: {asset}")
print(asset.id, asset.signed_url)
RustTrash and restore example
use nolgia_client::Client;
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_LENGTH};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut headers = HeaderMap::new();
    headers.insert(AUTHORIZATION, HeaderValue::from_str(
        &format!("Bearer {}", std::env::var("NOLGIA_TOKEN")?),
    )?);
    headers.insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
    let http = reqwest::Client::builder().default_headers(headers).build()?;
    let client = Client::new_with_client("https://api.nolgia.ai/v1", http);
    let id = std::env::var("ASSET_ID")?.parse::<uuid::Uuid>()?;
    client.delete_asset().id(id).send().await?;
    let asset = client.restore_asset().id(id).send().await?.into_inner();
    println!("{} {}", asset.id, asset.signed_url);
    Ok(())
}

Deletion returns 204 No Content, with no JSON. Restoration returns an asset; this is a schema-built excerpt, not a captured restore. The omitted model field records upload provenance for this uploaded image.

JSON200 restored Asset — schema-built excerpt
{
  "id": "11111111-1111-4111-8111-111111111111",
  "user_id": "22222222-2222-4222-8222-222222222222",
  "modality": "image",
  "signed_url": "https://storage.googleapis.com/example/reference.png?…",
  "expires_at": "2026-09-21T05:00:00Z",
  "status": "ready",
  "created_at": "2026-09-20T03:30:00Z"
}
Response field Meaning
id, user_id The original asset and its creator
modality, status Media kind and upload-completion state
signed_url, expires_at Current download URL and deadline
created_at Original creation time, preserved by restoration
deleted_at Cleared by restoration and omitted for this live asset
Method Path What it does
GET /assets/{id} Fetch one of the current user's assets with a fresh signed URL.
PATCH /assets/{id} Update one of the current user's assets (tags, display name, prompt, metadata, favorite).
DELETE /assets/{id} Move one of the current user's assets to the trash (soft delete).
POST /assets/{id}/restore Restore a trashed asset back into the library.
DELETE /assets/{id}/permanent Permanently delete one of the current user's assets.

Bring your own storage #

Enterprise organizations can connect an S3-compatible bucket. An owner or admin creates the connection, tests its credentials, and enables mirroring so assets are copied as they become ready. Existing ready assets can be backfilled, and objects in the bucket can be imported into the Library. The original Nolgia asset remains the id you use with the API.

Property Value
Availability Enterprise organization; owner or admin manages connections
Providers AWS S3 or compatible endpoints such as R2, MinIO and GCS interoperability
Automatic copy Enable mirror_enabled on the connection
Destination layout <prefix>/<yyyy>/<mm>/<asset_id>.<ext>
Progress Read the asset's mirrors array on GET /assets/{id}
Existing assets Queue a backfill for ready, non-trashed organization assets

mirrors is present only for an organization asset with at least one storage connection. Each entry names the connection, its copy status and, once available, the remote object key. Read that status before assuming the copy has completed.

Field Type Required Description
connection_id string Yes
status AssetMirrorStatus Yes
remote_key string, nullable No Object key in the customer's bucket once copied.
last_error string, nullable No Last copy failure; the worker retries up to five times with backoff before settling on error.
updated_at string Yes
Method Path What it does
GET /organizations/{id}/storage-connections List the organization's bring-your-own storage connections (owner or admin; Enterprise).
POST /organizations/{id}/storage-connections Connect an S3-compatible bucket to the organization (owner or admin; Enterprise).
PATCH /organizations/{id}/storage-connections/{connection_id} Update a storage connection (owner or admin; Enterprise).
DELETE /organizations/{id}/storage-connections/{connection_id} Disconnect a storage connection (owner or admin; Enterprise).
POST /organizations/{id}/storage-connections/{connection_id}/test Probe a storage connection (owner or admin; Enterprise).
POST /organizations/{id}/storage-connections/{connection_id}/import Import objects from the connected bucket into the organization library (owner or admin; Enterprise).
POST /organizations/{id}/storage-connections/{connection_id}/backfill Queue every ready organization asset for mirroring to this connection (owner or admin; Enterprise).

Summary #

Data type Default retention or lifetime Control
Live uploaded or generated asset Kept in the Library; download URL expiry does not delete it Trash or permanently delete the asset
Trashed asset and its bytes Purged 30 days after deleted_at Restore before purge, or permanently delete sooner
Asset download and thumbnail URLs Stable for about an hour; exact download expiry in expires_at Re-read the asset for a current signature
Signed upload URL 30 minutes Create a new upload after expiry
Prompt and enhanced image prompt Stored with the asset No storage opt-out or per-request expiry header
Public share link 30 days by default; 1–365 days at creation Set expires_in_days or revoke it
Organization mirror A copy in your connected bucket Manage the storage connection and your bucket's own lifecycle