Model APIs
Storage and data retention
On this page
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.
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 ''
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 ''
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);
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)
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.
{
"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 |

