Model APIs

Uploads and files

On this page
  1. Two ways to upload
  2. Small files
  3. Large files, step by step
    1. 1. Create the upload
    2. 2. PUT the bytes
    3. 3. Complete the asset
  4. Using your own storage
  5. Upload details
  6. Google Drive
  7. Expiry and access

Upload a file once, keep its asset id, and reuse it as a reference. Uploaded media lives in the same Library as generated media and can be filed into a project.

Uploads
Uploads

Two ways to upload #

Route Use it for Limit
Base64 JSON: POST /assets Small PNG, JPEG or WebP images About 10 MB decoded; the data field accepts at most 14,000,000 base64 characters
Signed PUT: POST /assets/uploads, PUT bytes, then complete Images, video, audio and GLB models Images: 100 MiB; video: 50 GiB; audio: 5 GiB; 3D: 200 MiB

The base64 route returns a stored asset immediately. The signed route first creates an uploading asset; only completion verifies the bytes and makes it ready. The CLI's upload command selects the upload flow for the file.

Small files #

Property Value
Endpoint POST /assets
Required fields content_type, data
File types image/png, image/jpeg, image/webp
Optional filing filename, project_id
Success 201 with an Asset

These are examples, not live upload captures. Set NOLGIA_TOKEN as in the Quick Start and replace reference.png with a small local image. The curl command uses macOS base64 -i; on GNU systems use base64 reference.png. Rust also uses the base64 crate for encoding.

shellSmall image upload example
curl -sS https://api.nolgia.ai/v1/assets \
  -H "Authorization: Bearer $NOLGIA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content_type":"image/png","filename":"reference.png","data":"<the file, base64-encoded>"}'
shellLocal file upload example
nolgia --json assets upload reference.png
TypeScriptSmall image upload example
import { readFile } from "node:fs/promises";
import { createNolgiaClient } from "@nolgia/sdk";

const nolgia = createNolgiaClient(process.env.NOLGIA_TOKEN!);
const { data: asset, error } = await nolgia.POST("/assets", {
  body: {
    content_type: "image/png",
    filename: "reference.png",
    data: (await readFile("reference.png")).toString("base64"),
  },
});
if (error) throw new Error(`${error.title}: ${error.detail ?? ""}`);
console.log(asset.id);
PythonSmall image upload example
import base64
import os
from pathlib import Path
from nolgia import AuthenticatedClient
from nolgia.api.assets import upload_asset
from nolgia.models import Asset, UploadAssetRequest

client = AuthenticatedClient(base_url="https://api.nolgia.ai/v1", token=os.environ["NOLGIA_TOKEN"])
asset = upload_asset.sync(client=client, body=UploadAssetRequest.from_dict({
    "content_type": "image/png",
    "filename": "reference.png",
    "data": base64.b64encode(Path("reference.png").read_bytes()).decode("ascii"),
}))
if not isinstance(asset, Asset):
    raise SystemExit(f"refused: {asset}")
print(asset.id)
RustSmall image upload example
use base64::{engine::general_purpose::STANDARD, Engine};
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 encoded = STANDARD.encode(std::fs::read("reference.png")?);
    let asset = client.upload_asset()
        .body_map(|b| b.content_type("image/png").data(encoded))
        .send().await?.into_inner();
    println!("{}", asset.id);
    Ok(())
}

The HTTP response is an Asset; this schema-built excerpt shows a stored image. The snippets print its reusable id. The omitted model field records upload provenance, not a generation model from the catalog.

JSON201 Asset — schema-built excerpt
{
  "id": "11111111-1111-4111-8111-111111111111",
  "user_id": "22222222-2222-4222-8222-222222222222",
  "modality": "image",
  "display_name": "reference",
  "mime_type": "image/png",
  "signed_url": "https://storage.googleapis.com/example/reference.png?…",
  "expires_at": "2026-09-21T05:00:00Z",
  "status": "ready",
  "created_at": "2026-09-21T03:30:00Z"
}
Response field Meaning
id Store this id and pass it to a supported asset-reference field
user_id, created_at Who uploaded the file and when
modality The media kind
display_name, mime_type Human-readable name and stored media type
signed_url, expires_at Temporary download location and its real expiry
status ready means the file is stored and usable

Large files, step by step #

Uploading large media Your app creates an upload with filename, content type and size. The Nolgia API returns a signed PUT URL valid for 30 minutes and an asset in the uploading state. Your app PUTs the bytes to storage with a matching Content-Type, then calls complete. The API verifies the size and marks the asset ready. Small files can be sent directly to POST /assets as base64. Your app Nolgia API Storage POST /assets/uploads filename, content_type, size_bytes small files instead: POST /assets, base64 PUT the bytes Content-Type must match POST /assets/uploads/ {id}/complete 201: upload_url signed PUT, valid 30 min asset uploading size verified, asset ready object at the signed URL
Upload handshake: create an upload, PUT the bytes, and complete the asset

1. Create the upload #

Property Value
Endpoint POST /assets/uploads
Success 201 with an AssetUpload
Required values Original filename, exact MIME type and exact byte size
Lifetime The signed PUT URL lasts 30 minutes
Field Type Required Description
filename string Yes Original filename, kept as asset metadata.
content_type one of video/mp4, video/quicktime, video/webm, audio/mpeg, audio/wav, audio/ogg, audio/webm, audio/mp4, image/png, image/jpeg, image/webp, model/gltf-binary Yes MIME type of the file. The signed PUT URL is bound to it, so the upload request must send exactly this Content-Type header.
size_bytes integer Yes Exact size of the file in bytes. Verified against the uploaded object on completion. Limits: 50 GiB for video, 5 GiB for audio, 100 MiB for images, 200 MiB for 3D models.
tags array of string No Tags to apply to the asset; trimmed, lowercased, and de-duplicated.
display_name string, nullable No Optional human-readable display name stored on the pre-created asset (trimmed). Defaults to empty.
project_id string, nullable No Files the uploaded asset into this caller-owned project directly (no tag matching involved); an unknown or foreign project returns 400. Without it, the asset lands in the default "Library" project.

For a local final-cut.mp4, measure the size instead of estimating it. Keep the response in upload for the next two calls.

shellCreate signed upload example
curl -sS https://api.nolgia.ai/v1/assets/uploads \
  -H "Authorization: Bearer $NOLGIA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"filename":"final-cut.mp4","content_type":"video/mp4","size_bytes":<the exact file size in bytes>}'
JSON201 AssetUpload — schema-built example
{
  "upload_id": "33333333-3333-4333-8333-333333333333",
  "asset_id": "44444444-4444-4444-8444-444444444444",
  "upload_url": "https://storage.googleapis.com/example/final-cut.mp4?…",
  "expires_at": "2026-09-21T04:00:00Z"
}
Field Type Required Description
upload_id string Yes Identifier for POST /assets/uploads/{id}/complete.
asset_id string Yes The pre-created asset (status uploading) the bytes will belong to.
upload_url string Yes Signed PUT URL. Upload with PUT <upload_url> and a Content-Type header exactly matching the declared content_type; no Authorization header is needed.
expires_at string Yes Expiry of upload_url (30 minutes after creation).

2. PUT the bytes #

Property Value
Destination The returned upload_url, used as-is
Method and body PUT with the raw file bytes
Header Content-Type: video/mp4, exactly matching the declaration
Authentication The URL contains its authorization; send no bearer token
shellPUT the file example
curl -sS -X PUT "<upload_url from the response>" -H "Content-Type: video/mp4" --upload-file final-cut.mp4
HTTPStorage PUT success — example
HTTP/1.1 200 OK
Content-Length: 0

The successful storage PUT has no JSON body. It does not complete the asset; the API still needs the verification call below.

3. Complete the asset #

Property Value
Endpoint POST /assets/uploads/{id}/complete; {id} is upload_id
Verification The stored object's size must equal declared size_bytes
Success 200 with the ready asset
Retry behavior Completing an already completed upload returns the same asset
Incomplete upload Missing object or mismatched size returns 409
shellComplete signed upload example
curl -sS -X POST "https://api.nolgia.ai/v1/assets/uploads/<upload_id from the response>/complete" -H "Authorization: Bearer $NOLGIA_TOKEN"
JSON200 Asset — schema-built completion excerpt
{
  "id": "44444444-4444-4444-8444-444444444444",
  "user_id": "22222222-2222-4222-8222-222222222222",
  "modality": "video",
  "mime_type": "video/mp4",
  "signed_url": "https://storage.googleapis.com/example/final-cut.mp4?…",
  "expires_at": "2026-09-21T05:00:00Z",
  "status": "ready",
  "created_at": "2026-09-21T03:30:00Z"
}
Response field Meaning
id The same id as the create response's asset_id
status Changes from uploading to ready after verification
signed_url, expires_at Download URL, separate from the upload URL
modality, mime_type The stored video's kind and media type
user_id, created_at Owner and original creation time

Default GET /assets listings hide unfinished uploads. Media duration, audio detection and thumbnails may arrive later through the media sweep; ready does not mean every optional metadata field is already populated.

Using your own storage #

Pass your own HTTPS URL to a request's supported *_url field, or a Library asset id to its *_asset_id / *_asset_ids field. The URL must remain reachable when processing starts. Reference support still depends on the model; see Common model arguments.

These two image request bodies illustrate the same choice. Use a reference-capable model and replace the URL or id with your own.

JSONPOST /generate/image with image_url — request example
{
  "model": "gpt-image-2",
  "prompt": "Place this product on a plain white background",
  "image_url": "https://media.example.com/product.png"
}
JSONPOST /generate/image with reference_asset_ids — request example
{
  "model": "gpt-image-2",
  "prompt": "Place this product on a plain white background",
  "reference_asset_ids": ["11111111-1111-4111-8111-111111111111"]
}

Both submit a job. This schema-built response applies to either request; follow the id with submit and poll.

JSON202 Job — schema-built example
{
  "id": "55555555-5555-4555-8555-555555555555",
  "user_id": "22222222-2222-4222-8222-222222222222",
  "modality": "image",
  "model": "gpt-image-2",
  "status": "queued",
  "created_at": "2026-09-21T03:30:00Z",
  "updated_at": "2026-09-21T03:30:00Z"
}
Response field Meaning
id The durable job id to poll
status queued means accepted, not finished
user_id, modality, model Caller and selected generation route
created_at, updated_at Acceptance and latest job-update times

Upload details #

Property Value
Base64 limit About 10 MB decoded; PNG, JPEG and WebP only
Signed-upload image limit 100 MiB
Signed-upload video limit 50 GiB
Signed-upload audio limit 5 GiB
Signed-upload 3D limit 200 MiB
PUT content type Must exactly match the declared content_type
Signed-upload tags Up to 10; trimmed, lowercased and deduplicated; completion applies tag-based project associations
Direct project filing Set project_id; unknown or foreign project returns 400; omitted means the default Library project
Display name Supply filename for a recognizable name; signed uploads also accept display_name

Accepted MIME types for signed uploads are generated from the request schema:

Google Drive #

Import a media file into the Library or export an asset to Google Drive. Both calls use a short-lived Google OAuth token with the drive.file scope for that request only. Import accepts the signed-upload media types and size limits; Google Docs, Sheets, and Slides are not media imports. These calls are available on Studio plans, Team, and Enterprise.

Method Path What it does
POST /assets/imports/google-drive Import a Google Drive file into the library.
POST /assets/{id}/exports/google-drive Save an asset to Google Drive.

Expiry and access #

Upload URLs and download URLs have different lifetimes. Read Storage and data retention for signed URL renewal and deletion, and File access controls for Library scope and share links that remain useful after a download URL expires.