Organizing and finding assets
A library is only as useful as what you can retrieve from it. This page covers the querying half of the media library: the filters, the two endpoints that accept them, and how to save a query rather than rebuild it.
Two listing endpoints
They are not interchangeable, and picking the wrong one is a common early mistake:
| Endpoint | For |
|---|---|
GET /files | Any repository. repo_type is required: files are always scoped to one, never listed across the workspace. Plain column filters: name, type, size, status, dates. |
GET /media-files | The media library (repo_type=media) or generated media (repo_type=generated). The full filter vocabulary below, each file's album membership, and semantic and face search. |
For asset-management work, use GET /media-files. It returns album membership alongside
each file rather than listing one album; that is af_album, one filter among many.
Repository parameters
repo_type names what kind of thing owns the files, and repo_id names which one:
repo_type | repo_id | Lists |
|---|---|---|
media | — | The shared media library, what people uploaded. A library takes no id. |
generated | — | What the platform produced: AI images and infographics, wherever they were made. |
ds | knowledge base id | The documents a knowledge base indexes. |
thread | conversation id | What was attached to a conversation, and what was generated in it. |
design | design id | A design's assets and rendered previews. |
prompt | prompt id | The references attached to a saved prompt. |
A file can sit in more than one repository at once, and either containment is readable:
an image generated inside a conversation carries both generated and its thread, so it
is returned by both listings.
Reading a repository means reading the object that owns it, so that object's access rules
apply on top of each file's. Several repositories have their own collection, which is the
more direct way to ask: GET /knowledge-bases/{id}/files, GET /threads/{id}/files,
GET /designs/{id}/files.
Both endpoints answer with the standard collection envelope:
Code
Each row in the media library adds file_albums: every album the file belongs to,
resolved, so you do not need a second call to render membership:
Code
The filter vocabulary
Filters combine with AND. Where a filter takes a list, the values inside it combine with
OR, so tags=harbor&tags=sunset means "either tag", and adding orientation=Landscape
narrows that to landscape files.
Core filters
| Filter | |
|---|---|
search | Free text over the file name and, for generated images, the prompt that made them. |
af_album | Files in one album. |
favorite=true | The calling user's favorites. Favorites are per person, not per workspace. |
fileType | Image, Video, Audio or Document. Repeatable. |
file_created, photoTakenDate | Time ranges. photoTakenDate is when the photo was taken; file_created is when it arrived. They differ for anything imported from an archive. |
file_state_item | Files sitting at one state of your review workflow. |
aiGenerated | Whether the platform generated the image. |
excludeWorkflow=true | Hides intermediate files produced by workflow runs. |
Tags
Two systems, deliberately kept separate:
-
tags: what the AI identified. Free-form labels from analysis. Filter withtags=harbor&tags=boat. -
mediaTags: what your organization defined. Structured groups you define, passed as a JSON object mapping group to values:Code
Write media tags with PUT /files/{id}/media-tags for one file, or POST /files/actions/set-media-tags for many. The bulk form merges by default and removes when
you pass remove: true, and it reports what it actually changed:
Code
The difference is files you cannot write to. Compare the two numbers rather than treating a 200 as confirmation that all of them were updated.
Analysis filters
These read the AI's structured output, so they match only files that reached ready. See
AI enrichment for what produces them.
| Filter | |
|---|---|
flags | Anything the analysis flagged for attention. Repeatable. |
photoRating | Overall quality score, 1 to 5, as a range: photoRating[0]=4&photoRating[1]=5. |
peopleCount | Number of people in the shot, as a range. |
gender, role, age | Attributes of the people in the shot. age is a range. |
orientation | Portrait or Landscape, computed from EXIF dimensions. |
dpi | Pixel density range, the filter for whether a file is good enough to print. |
custom | Fields from your own analysis schemas, as {"field":["value"]}. |
Faces
| Filter | |
|---|---|
has_faces=true | Any photo containing a countable face. |
face_person | Photos containing one named person. |
face_embedding | Photos containing a face resembling one you supply. See people and faces. |
Meaning
embedding_search searches by what an image is of rather than what it is called,
and works on files whose analysis has produced embeddings:
Code
Matching rows carry a similarity score, and results are ordered by it.
similarityThreshold tightens or loosens the cutoff. AI enrichment
covers this in full.
Ranges
Range filters take two values, either repeated (age=25&age=40) or as
{"min":25,"max":40}. Both ends are inclusive and both are required; there is no
open-ended form.
Albums
Manual albums are explicit lists. Create one, then add and remove files:
Adding is idempotent and reports the result:
Code
skipped counts files already in the album, and missing counts files that do not exist
or are not visible to you. Re-sending the same list is safe.
You can also skip this step entirely: album_ids on the upload
request files a file at the moment it is created.
Smart albums are a saved filter rather than a list. Their contents are whatever currently matches, so files join and leave automatically:
Code
query_search is the same filter object you would have sent as query parameters. PATCH /albums/{id}/smart changes it later, and reading a smart album returns the filter as
album_query_search so you can show people what it selects on.
Albums nest through album_parent, and GET /albums?album_parent=<id> walks one level.
A smart album is how you save a filter. There is no separate saved-search resource on this surface: to keep a query, save it as a smart album and read it back as one.
Bulk actions
Three bulk endpoints take a file_ids array and apply one change:
POST /files/actions/set-media-tags | Add or remove media tags. |
POST /files/actions/transition | Move files to a target_state_id in the media status flow. |
POST /files/actions/reanalyze | Re-run AI analysis. Consumes credits. |
Each skips files you cannot write to rather than failing the batch, and each reports counts. Most housekeeping integrations combine a filtered list with one of these actions: query for what is wrong, then hand the ids to the action.
Sorting and paging
sort=-file_created is newest first, and sort=file_name is A to Z. The media library
adds a deterministic tiebreaker of its own, so equal sort values do not reshuffle between
pages and infinite scroll does not show duplicates.
Page with cursor rather than offset (see pagination). Media libraries
are exactly the case cursors exist for: a deep offset gets slower the further in you go.
Next steps
- AI enrichment explains what fills in the analysis filters above.
- People and faces covers the face filters, and naming who is in a photo.
- Delivering assets is how you get the files you found back out.
