List Project Media

September 1, 2026

Table of contents

  1. What is listed
  2. Uploads vs generated media
  3. Request Headers
  4. Path Parameters
  5. Query Parameters
  6. Responses
  7. Model
  8. Examples
  9. 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.

https://api.useapi.net/v1/google-flow/assets/media/email?projectId=

Request Headers

Authorization: Bearer {API token}

Path Parameters

  • email is required, URL-encoded. The Google Flow account holding the project.

Query Parameters

  • projectId is optional. Defaults to the project this account currently writes to. Pass a projectId from GET /assets/projects/email to read any other project on the account. It is required when the account has no project on file, in which case the call returns 400 without it.

There is no pagination — one call returns the whole project. A large project can return several hundred entries.

Responses

  • 200 OK

    {
      "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 200 with an empty array, not 404.

    {
      "email": "[email protected]",
      "projectId": "3a18acb1-2c6e-478b-bcec-2df19cb8edab",
      "count": 0,
      "likelyUploads": 0,
      "media": []
    }
    
  • 400 Bad Request

    No projectId was given and the account has no project on file. Pass one explicitly — GET /assets/projects/email lists every project the account holds media in.

    {
      "error": "Parameter projectId is required (this account has no project on file)"
    }
    

    The projectId does 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/email rather 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
        }
      }
    }
    
  • 401 Unauthorized

    Invalid API token.

    {
      "error": "Unauthorized"
    }
    
  • 404 Not Found

    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/email and 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
  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']}")
    

Try It