Skip to content

List generations

Page through the generations on an account, filter it down, and download them.

On this page

The library is the generations on an account. List it to browse what is there, narrow it with filters, and download individual items.

GEThttps://api2.rundiffusion.com/api/v2/library
AcceptsOAuth device flowPersonal API Access TokenCompany API Access Token

Request

Headers

AuthorizationstringRequired
Bearer token. This endpoint accepts an OAuth device flow token, a Personal API Access Token, or a Company API Access Token. See Authentication.Authorization: Bearer eyJhbGciOi…

Every query parameter is optional. With none of them you get your own generations on your personal account, newest first.

Which pool of generations you are reading follows team_id, the same way it does on every endpoint: omit it for your personal account, name a team for that team's. Here it also takes several team IDs separated by commas, to read across teams in one page.

curl "https://api2.rundiffusion.com/api/v2/library?limit=24" \
  -H "Authorization: Bearer $RUNDIFFUSION_TOKEN"

Paging

Query

cursorstringoptional
Opaque pagination token. When a response has has_more true, pass its next_cursor here to get the following page. Do not construct or parse one.https://api2.rundiffusion.com/api/v2/library?cursor=eyJhIjoiMjAyNi0…
limitintegeroptionaldefault 24
Page size, from 1 to 24.https://api2.rundiffusion.com/api/v2/library?limit=10

Scope

The account selection names the pool; scope decides reach within it. mine, the default, is your own generations. all is every member's, and it takes the Can manage everyone's generations and boards (MANAGE_ALL_GENERATIONS) permission.

Your own rows on a team, the default, need no permission at all:

bash
curl "https://api2.rundiffusion.com/api/v2/library?team_id=Tq8vNc…" \
  -H "Authorization: Bearer $RUNDIFFUSION_TOKEN"

Whole-team reads take scope=all, and can span teams by naming several. The permission is checked on every team named: a partly-authorized list is refused with the failing teams in the error, never quietly narrowed to the ones that passed, because a page from the narrowed list would be indistinguishable from the full answer.

bash
curl "https://api2.rundiffusion.com/api/v2/library?team_id=Tq8vNc…,Wm2xLp…&scope=all" \
  -H "Authorization: Bearer $RUNDIFFUSION_TOKEN"

Query

team_idstringoptionalAccepts multiple
The team or teams to read. Several match any of them. Omit it to read your personal account. Part of the account selection rather than a filter, so it behaves identically on every endpoint.https://api2.rundiffusion.com/api/v2/library?team_id=Tq8vNc…,Rn4tKp…
scopestringoptionaldefault mine
Whose rows within the selected account. mine is the caller's own generations. all is every member's; it takes a team account and requires MANAGE_ALL_GENERATIONS on every team named in team_id.https://api2.rundiffusion.com/api/v2/library?team_id=Tq8vNc…&scope=all
user_idstringoptionalAccepts multiple
Narrow scope=all to named members. Several match any of them. On the ordinary listing it selects whose generations; with sort=favorited it selects whose favorites. Under scope=mine you are already the answer, so sending it there is a 400 rather than being quietly overridden.https://api2.rundiffusion.com/api/v2/library?team_id=Tq8vNc…&scope=all&user_id=k3PqV9…

Filters

Query

board_idstringoptionalAccepts multiple
Narrow to a board. Applies to both the ordinary library and the favorites view. Several match any of them.https://api2.rundiffusion.com/api/v2/library?board_id=Rn4tKp…,Tq8vNc…
node_idstringoptionalAccepts multiple
Narrow to generations produced by a board node. Several match any of them. A board can hold the same tool more than once, so this is finer than board_id.https://api2.rundiffusion.com/api/v2/library?node_id=Nd8pKw…,Nd4kWs…
tool_idstringoptionalAccepts multiple
Narrow to generations produced by a tool. IDs come from List tools. Several match any of them.https://api2.rundiffusion.com/api/v2/library?tool_id=1kCVin…,Tl9xBv…
aspect_ratiostringoptionalAccepts multiple
Aspect-ratio bucket, not an exact ratio. Anything that does not land in a listed bucket is OTHER. Several match any of them.https://api2.rundiffusion.com/api/v2/library?aspect_ratio=16:9,1:1
resolutionstringoptionalAccepts multiple
Resolution bucket measured on the long edge. Percent-encode the plus in 4K+ as 4K%2B, since a bare + means a space in a query string. Several match any of them.https://api2.rundiffusion.com/api/v2/library?resolution=2K,4K%2B
model_family_tool_tag_idstringoptionalAccepts multiple
Narrow to a model-family tool tag. IDs come from List tool tags. Several match any of them.https://api2.rundiffusion.com/api/v2/library?model_family_tool_tag_id=Mf3xQ8…,Mf7dPq…
use_case_tool_tag_idstringoptionalAccepts multiple
Narrow to a use-case tool tag. IDs come from List tool tags. Several match any of them.https://api2.rundiffusion.com/api/v2/library?use_case_tool_tag_id=Uc9wLm…,Uc2hTn…
media_tool_tag_idstringoptionalAccepts multiple
Narrow to a media tool tag. IDs come from List tool tags. Several match any of them.https://api2.rundiffusion.com/api/v2/library?media_tool_tag_id=Md5kR8…,Md1nVj…
start_utcstring (ISO 8601)optional
Start of the window, inclusive, in UTC. A generation created at exactly this instant is included.https://api2.rundiffusion.com/api/v2/library?start_utc=2026-05-01T00:00:00Z
end_utcstring (ISO 8601)optional
End of the window, exclusive, in UTC. A generation created at exactly this instant is NOT included, so a whole month is start_utc=2026-05-01T00:00:00Z with end_utc=2026-06-01T00:00:00Z. Must be after start_utc, or the request is rejected with 400.https://api2.rundiffusion.com/api/v2/library?start_utc=2026-05-01T00:00:00Z&end_utc=2026-06-01T00:00:00Z

Favorites

Favorites are two parameters because they are two independent questions. favorited decides which generations come back. sort decides what order they come back in.

Query

favoritedbooleanoptionaldefault false
When true, return only generations the caller has favorited. It is an ordinary filter, so it stacks with every other one and works at either scope: pair it with scope=all to see your own stars inside a whole team library.https://api2.rundiffusion.com/api/v2/library?favorited=true
sortstringoptionaldefault created
Result order. created is newest-generated first, the same order as the rest of the library. favorited is most-recently-starred first, and requires favorited=true because ordering by when something was favorited is meaningless for things that are not.https://api2.rundiffusion.com/api/v2/library?favorited=true&sort=favorited

Pick sort by the question you are answering. "What did I star lately" is sort=favorited. "Show my library, starred only" is the default sort=created, which leaves the usual ordering alone.

Response

200 OK with one cursor page of generations.

json
{
  "data": [
    {
      "id": "Kp7mZq…:3f2a9c14-…",
      "run_id": "Kp7mZq…",
      "result_id": "3f2a9c14-…",
      "type": "VID",
      "url": "https://rundiffusion.com/...",
      "thumb_url": "https://rundiffusion.com/...",
      "mime_type": "video/mp4",
      "width": 1080,
      "height": 1920,
      "duration_seconds": 15.1,
      "size_bytes": 7729000,
      "created": "2026-05-28T22:33:52Z",
      "tool_id": "1kCVin…"
    }
  ],
  "has_more": true,
  "next_cursor": "eyJhIjoiMjAyNi0…",
  "last_cursor": null
}

Top level

dataarray
The generations on this page, newest first. Empty when nothing matches.
has_moreboolean
Whether more pages exist beyond this one. This is the flag to branch on when paging.
next_cursorstring | null
Pass this back as cursor to fetch the next page. Null on the last page. This is the one to page with.
last_cursorstring | null
Echoes the cursor you sent on this request, so a response can be matched to what produced it. Null on the first page. It points backwards, so paging with it loops.

Generation object

idstring
run_id and result_id joined by a colon. This is how a single item is addressed, and you can pass it back whole as a LIBRARY_REF input without splitting it. Example: Kp7mZq…:3f2a9c14-….
run_idstring
The run that produced this item, as a 20-character opaque string. One run can produce several items.
result_idstring
This item within its run.
typestring
What kind of generation this is. The library serves renderable generations.
urlstring | null
Signed download URL, valid for roughly seven days. Treat it as opaque and re-list to refresh it rather than storing it.
thumb_urlstring | null
Signed URL to a 512x512 WebP thumbnail, same seven-day expiry. Falls back to the same value as url in the short window after a run completes but before the thumbnail is generated, so there is always something displayable.
mime_typestring | null
MIME type of the stored file, for example image/jpeg or video/mp4.
widthinteger | null
Pixel width. Null for formats without one.
heightinteger | null
Pixel height. Null for formats without one.
duration_secondsnumber | null
Runtime in seconds for video. Null for still generations.
size_bytesinteger | null
Size of the file at url, in bytes.
createdstring (ISO 8601)
When it was created, in UTC.
tool_idstring | null
The tool that produced the item. Pass it back as tool_id to find everything else from the same tool.

Paging through everything

let cursor = null;
const items = [];

do {
  const url = new URL('https://api2.rundiffusion.com/api/v2/library');
  url.searchParams.set('limit', '24');
  if (cursor) url.searchParams.set('cursor', cursor);

  const page = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.RUNDIFFUSION_TOKEN}` },
  }).then(r => r.json());

  items.push(...page.data);
  cursor = page.has_more ? page.next_cursor : null;
} while (cursor);

A page always holds as many items as you asked for until the library runs out. Filtering happens before the page is assembled, so a page never comes back short because of generations that were withheld or deleted.

Identifying an item

id is the run_id and result_id joined by a colon, and that pair is how an item is addressed anywhere else it comes up. Treat it as opaque and pass it whole: the two halves are also returned separately, so there is never a reason to split one yourself. Get a generation fetches one by it, and Delete a generation removes one.

Errors

400VALIDATION_ERROR
A parameter failed validation. The common causes are a malformed team ID list in scope, an end_utc that is not after start_utc, a limit outside 1 to 24, and a value outside an enum. Sending a retired parameter lands here too, with the replacement named in the message.
401UNAUTHENTICATED
Missing, malformed, or expired token. Refresh it and retry.
403PERMISSION_DENIED
The caller cannot read the requested scope: scope=all without MANAGE_ALL_GENERATIONS on every team named in team_id. The error names the teams missing it.
429RATE_LIMITED
Too many requests. Back off and retry per the Retry-After header. See Rate limits.

See Errors for the full envelope and the code list.

View as Markdown