List Project Media
September 1, 2026 (October 10, 2026)
Table of contents
- What is listed
- Uploads vs generated media
- Very large projects
- Request Headers
- Path Parameters
- Query Parameters
- Responses
- Model
- Examples
- Try It
List the media held in one project on a Google Flow account. Every entry comes back with a mediaGenerationId you can pass straight to DELETE /assets/email or GET /assets/mediaGenerationId.
This is the endpoint that shows you your uploads. Files you send with POST /assets stay on the Google account after the generation that used them is finished, and nothing removes them on its own — they simply accumulate. likelyUploads counts them, and likelyUpload marks each one.
Find a project id with GET /assets/projects/email, or omit projectId to read the project this account currently writes to.
What is listed
Two collections are merged into one media array: the project’s own timeline, and media attached to the project from elsewhere. The second is where uploads normally sit, and it is usually much the larger of the two — on a real account the project’s own timeline held 8 entries against 292 attached ones, every one of them an upload, some more than nine months old.
Both are listed together because both are stored on the account, both count toward it, and both can be deleted the same way.
Uploads vs generated media
likelyUpload reflects how Google itself recorded the media — as something you uploaded, or as something Flow generated. It is not inferred from the presence of a prompt or any other heuristic.
It is likelyUpload rather than isUpload for one reason: an entry Google records as neither stays false. Those show up as mediaType: "OTHER" and are left out of the likelyUploads count rather than being offered up for deletion on a guess.
Very large projects
One call returns at most 25,000 entries. When a project holds more, the response carries truncated: true. The project’s own timeline comes first, so the attached uploads show up once the timeline holds fewer than 25,000 entries.
There is no cursor. Google sends the whole project on every call, in no particular order, so a later page would cost as much as reading everything. To work through a large project, delete the entries you no longer need with DELETE /assets/email and call again — the next call returns entries the previous one did not. A call that keeps getting back entries you want to keep will keep returning them.
A project of tens of thousands of entries is also slow to read: expect 20 seconds to over a minute per call. The fastest way out is to start the account on a fresh project:
- In Google Flow, delete the project whose id is
project.projectIdin GET /accounts/email. - Add the account again with POST /accounts. The API sees the project is gone and creates a new, empty one for the account.
Everything in the deleted project is gone for good. Characters and voices are kept: they live in a separate project.
https://api.useapi.net/v1/google-flow/assets/media/
Request Headers
Authorization: Bearer {API token}
API tokenis required, see Setup useapi.net for details.
Path Parameters
emailis required, URL-encoded. The Google Flow account holding the project.
Query Parameters
projectIdis optional. Defaults to the project this account currently writes to. Pass aprojectIdfrom GET /assets/projects/emailto read any other project on the account. It is required when the account has no project on file, in which case the call returns400without it.
One call returns up to 25,000 entries. See Very large projects when a project holds more.
Responses
-
{ "email": "[email protected]", "projectId": "3a18acb1-2c6e-478b-bcec-2df19cb8edab", "count": 591, "likelyUploads": 388, "media": [ { "mediaGenerationId": "user:12345-email:6a6f...-image:0115f3c1-...redacted...", "mediaType": "IMAGE", "createTime": "2026-06-14T00:03:47.401463Z", "likelyUpload": true }, { "mediaGenerationId": "user:12345-email:6a6f...-video:a1d95d21-...redacted...", "mediaType": "VIDEO", "createTime": "2026-07-26T21:07:56.856451Z", "likelyUpload": false } ] }An empty project returns
200with an empty array, not404.{ "email": "[email protected]", "projectId": "3a18acb1-2c6e-478b-bcec-2df19cb8edab", "count": 0, "likelyUploads": 0, "media": [] } -
No
projectIdwas given and the account has no project on file. Pass one explicitly — GET /assets/projects/emaillists every project the account holds media in.{ "error": "Parameter projectId is required (this account has no project on file)" }The
projectIddoes not exist on this account, or is not a well-formed project id. Google’s own rejection is passed through unchanged, which is why this one does not read like the errors above. Both cases look identical, so check the value against GET /assets/projects/emailrather than trying to tell them apart from the response.{ "error": { "json": { "message": "Bad Request", "code": -32600, "data": { "code": "BAD_REQUEST", "httpStatus": 400, "path": "flow.projectInitialData", "zodError": null }, "status": 400 } } } -
Invalid API token.
{ "error": "Unauthorized" } -
The account named in the path is not configured for this token. List what is configured with GET /accounts.
{ "error": "Google Flow account [email protected] not found" } -
596 Session Error
Google session refresh failed. The account needs to be reconfigured. Delete the account using DELETE /accounts/
emailand add it again by strictly following the procedure in Setup Google Flow.{ "error": "Failed to refresh session: 500 Internal Server Error" }
Model
{
email: string // Echo of the path parameter
projectId: string // The project read, whether passed or defaulted
count: number // Length of media[]
likelyUploads: number // How many entries have likelyUpload: true
truncated?: true // Present when the project holds more than the 25,000 entries returned
media: [{
mediaGenerationId: string // Send to DELETE /assets or GET /assets/{mediaGenerationId}
mediaType: 'IMAGE' | 'VIDEO' | 'OTHER'
createTime?: string // ISO 8601, absent on records Google returns without one
likelyUpload: boolean // True when Google recorded this as an upload
}]
error?: string // Present only on error responses
}
Examples
-
TOKEN='YOUR_API_TOKEN' EMAIL='[email protected]' ENCODED=$(printf %s "$EMAIL" | jq -sRr @uri) # The account's current project RESP=$(curl -s -H "Authorization: Bearer $TOKEN" \ "https://api.useapi.net/v1/google-flow/assets/media/$ENCODED") jq '{projectId, count, likelyUploads}' <<<"$RESP" # A specific project, listing the uploads oldest first PROJECT_ID='6db64a76-90a9-4ecd-99f0-cc524ec2b2af' curl -s -H "Authorization: Bearer $TOKEN" \ "https://api.useapi.net/v1/google-flow/assets/media/$ENCODED?projectId=$PROJECT_ID" \ | jq '[.media[] | select(.likelyUpload)] | sort_by(.createTime) | .[] | "\(.createTime) \(.mediaType) \(.mediaGenerationId)"' -r -
const token = 'YOUR_API_TOKEN'; const email = '[email protected]'; const params = new URLSearchParams(); // Omit projectId to read the account's current project // params.set('projectId', '6db64a76-90a9-4ecd-99f0-cc524ec2b2af'); const url = `https://api.useapi.net/v1/google-flow/assets/media/${encodeURIComponent(email)}` + (params.toString() ? `?${params}` : ''); const resp = await fetch(url, { headers: { 'Authorization': `Bearer ${token}` } }); if (!resp.ok) throw new Error(`${resp.status} ${await resp.text()}`); const { projectId, count, likelyUploads, media } = await resp.json(); console.log(`${projectId}: ${count} media, ${likelyUploads} uploads`); const uploads = media .filter(m => m.likelyUpload) .sort((a, b) => (a.createTime ?? '').localeCompare(b.createTime ?? '')); for (const m of uploads.slice(0, 10)) console.log(`${m.createTime} ${m.mediaType} ${m.mediaGenerationId}`); -
import requests from urllib.parse import quote token = 'YOUR_API_TOKEN' email = '[email protected]' url = f'https://api.useapi.net/v1/google-flow/assets/media/{quote(email, safe="")}' # Omit projectId to read the account's current project params = {} # params['projectId'] = '6db64a76-90a9-4ecd-99f0-cc524ec2b2af' resp = requests.get(url, headers={'Authorization': f'Bearer {token}'}, params=params) resp.raise_for_status() data = resp.json() print(f"{data['projectId']}: {data['count']} media, {data['likelyUploads']} uploads") uploads = sorted((m for m in data['media'] if m['likelyUpload']), key=lambda m: m.get('createTime') or '') for m in uploads[:10]: print(f"{m.get('createTime')} {m['mediaType']} {m['mediaGenerationId']}")