Research sources

September 29, 2026

Table of contents

  1. Request Headers
  2. Request Body
  3. Responses
  4. Model
  5. Examples
  6. Try It

Let Google search the web for a notebook, the “Discover sources” and “Deep Research” features of the Gemini Notebook web app. Pass a query and a type:

  • fast (the default) is Discover sources. It returns web sources with a title and a one-line description of each, plus a one-line summary of what it found. In our tests it returned 10 sources in about 15 seconds.
  • deep is Deep Research. Google researches the question at length and writes a report in Markdown, with the web sources it read. Each source says whether the report cites it (cited). It took 3.3 to 4.2 minutes in our tests (September 2026).

Discover sources can also search the account’s own Google Drive instead of the web: send source: "drive" with type: "fast". Deep Research searches the web only. A Drive result links to the file, carries its driveFileId, and its mimeType for the file types seen so far (a Google Doc and a Word .docx in our tests, September 2026). Google leaves out Drive files that are already sources of the notebook, so a Drive search on a notebook that holds every matching file finds nothing.

A run that finds nothing completes normally, with result.sources: [] and result.noResults: true. There is nothing to import from it.

A research run finds sources but does not add them. The notebook is unchanged until you pick what to keep and add it with POST /research/import: any of the sources, and for Deep Research the report itself as a Markdown source.

Every research run is a job, like a Studio artifact. Poll it with GET /jobs/jobid, or pass replyUrl to receive the finished record by webhook. DELETE /jobs/jobid stops a run at Google. A research job holds one of the account’s maxJobs slots while it runs, see GET /jobs.

Deep Research spends Google’s usage window, like a Studio job. GET /accounts/email lists Google’s cost estimates for research under the actions deep_research and fast_research.

Sync, async and webhooks

  • mode: "sync" (the default) waits up to 90 seconds for the result. A run that finishes in time returns 200 with its result, which is the usual outcome for fast. A run still going at 90 seconds returns 202 with the job record, the usual outcome for deep, and you keep polling GET /jobs/jobid. If your connection drops during the wait, the job carries on and can still be polled.
  • mode: "async" returns 201 with the job record at once.
  • The API checks running jobs every ~15 seconds. A research job still running after 40 minutes is failed with error.code: "timeout".
  • replyUrl receives one POST of the final job record when the job completes or fails.

https://api.useapi.net/v1/gemini-notebook/research

Request Headers
Authorization: Bearer {API token}
Content-Type: application/json
# Alternatively you can use multipart/form-data
# Content-Type: multipart/form-data
Request Body
{
  "notebook": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
  "query": "Why did the Apollo 11 landing nearly abort?",
  "type": "deep",
  "mode": "async",
  "replyUrl": "https://your-domain.com/webhook",
  "replyRef": "deep-1"
}
  • notebook is required, the notebook id returned by POST /notebooks or GET /notebooks. The id names its account, so the job runs there.
  • query is required, what to research.
    Length: 1 to 2,000 characters.
  • type is optional, the kind of research.
    Supported values: fast (Discover sources, default), deep (Deep Research).
  • source is optional, where to search.
    Supported values: web (default), drive (the account’s Google Drive, type: "fast" only). drive with type: "deep" returns 400.
  • mode is optional, sync (default) or async. See Sync, async and webhooks.
  • replyUrl is optional, a public http(s) URL that receives one POST of the job record when the job completes or fails. See GET /jobs/jobid for the record’s shape.
  • replyRef is optional, your own reference echoed back in the job record, up to 1024 characters.
Responses
  • 200 OK

    Sync mode, finished within 90 seconds (Discover sources, list shortened):

    {
      "jobid": "job:526bc256-d897-493a-9ebc-7c9f35ca4428-user:[email protected]:gemini_notebook",
      "email": "[email protected]",
      "type": "research",
      "status": "completed",
      "notebook": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
      "created_at": "2026-09-29T04:10:07.338Z",
      "request": {
        "notebook": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
        "query": "Apollo 11 lunar module guidance computer alarms",
        "type": "fast"
      },
      "completed_at": "2026-09-29T04:10:23.751Z",
      "result": {
        "mode": "fast",
        "query": "Apollo 11 lunar module guidance computer alarms",
        "summary": "Navigate the technical causes, software design, and human decisions behind the famous Apollo 11 guidance computer alarms.",
        "sources": [
          {
            "url": "https://www.ibiblio.org/apollo/Documents/CherryApollo11Exegesis.pdf",
            "title": "Exegesis of the 1201 and 1202 Alarms Which Occurred During the Mission G Lunar Landing - Ibiblio",
            "description": "Technical exegesis explaining the exact mechanism of 1201/1202 alarms.",
            "cited": true
          },
          {
            "url": "https://www.nasa.gov/wp-content/uploads/static/apollo50th/pdf/A11_MissionReport.pdf",
            "title": "APOLLO 11 MISSION REPORT NOVEMBER 1969 - NASA",
            "description": "Official NASA report detailing the onboard timeline and initial findings.",
            "cited": true
          },
          {
            "url": "https://science.nasa.gov/people/margaret-hamilton/",
            "title": "Margaret Hamilton - NASA Science",
            "description": "Overview of Margaret Hamilton's software engineering innovations for Apollo.",
            "cited": true
          }
        ]
      }
    }
    

    A completed Deep Research job, from GET /jobs/jobid or the webhook (report and list shortened):

    {
      "jobid": "job:139f798f-b450-45c3-9dfa-57cd9e8e8581-user:[email protected]:gemini_notebook",
      "email": "[email protected]",
      "type": "research",
      "status": "completed",
      "notebook": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
      "created_at": "2026-09-29T04:11:57.062Z",
      "request": {
        "notebook": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
        "query": "Why did the Apollo 11 landing nearly abort?",
        "type": "deep"
      },
      "replyUrl": "https://your-domain.com/webhook",
      "replyRef": "deep-1",
      "completed_at": "2026-09-29T04:15:17.664Z",
      "result": {
        "mode": "deep",
        "query": "Why did the Apollo 11 landing nearly abort?",
        "report": {
          "title": "Systemic Stress and Cascading Anomalies: An Engineering Analysis of the Apollo 11 Lunar Landing Near-Abort",
          "markdown": "# Systemic Stress and Cascading Anomalies: An Engineering Analysis of the Apollo 11 Lunar Landing Near-Abort\n\nThe Apollo 11 lunar landing on July 20, 1969, represents a monumental achievement in aerospace engineering, yet the final powered descent of the Lunar Module (*Eagle*, LM-5) brought the mission to the threshold of an abort call [cite: 1, 2]..."
        },
        "sources": [
          {
            "url": "https://space.stackexchange.com/questions/37368/what-were-the-problems-on-the-apollo-11-lunar-module",
            "title": "What were the problems on the Apollo 11 lunar module?",
            "description": "Comprehensive breakdown of computer alarms and low fuel issues.",
            "cited": true
          },
          {
            "url": "https://www.discovermagazine.com/apollo-11s-1202-alarm-explained-185",
            "title": "Apollo 11's \"1202 Alarm\" Explained - Discover Magazine",
            "description": "Detailed explanation of the 1202 alarms and computer overload.",
            "cited": true
          },
          {
            "url": "https://space.stackexchange.com/questions/49244/why-didnt-nasa-simulate-the-conditions-leading-to-the-1202-alarm-during-apollo",
            "title": "Why didn't NASA simulate the conditions leading to the 1202 alarm during Apollo 11?",
            "description": null,
            "cited": false
          }
        ]
      }
    }
    
  • 201 Created

    Async mode. The job is created and returned at once. Poll GET /jobs/jobid until status is completed or failed.

    {
      "jobid": "job:139f798f-b450-45c3-9dfa-57cd9e8e8581-user:[email protected]:gemini_notebook",
      "email": "[email protected]",
      "type": "research",
      "status": "processing",
      "notebook": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
      "created_at": "2026-09-29T04:11:57.062Z",
      "request": {
        "notebook": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
        "query": "Why did the Apollo 11 landing nearly abort?",
        "type": "deep"
      },
      "replyUrl": "https://your-domain.com/webhook",
      "replyRef": "deep-1"
    }
    
  • 202 Accepted

    Sync mode, still running after 90 seconds. Poll GET /jobs/jobid for the result. The job record is the same as the 201 one.

  • 400 Bad Request

    A missing or invalid parameter.

    {
      "error": "Parameter type (slow) valid values: fast,deep",
      "code": 400
    }
    
    {
      "error": "Parameter query is required",
      "code": 400
    }
    
    {
      "error": "Deep Research searches the web only; use type fast with source drive",
      "code": 400
    }
    
  • 401 Unauthorized

    Invalid API token.

    {
      "error": "useapi.net ⁝ Unauthorized",
      "code": 401
    }
    
  • 403 Forbidden

    The notebook id belongs to a different API token, or Google does not allow this on the account’s plan.

    {
      "error": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55 does not belong to this API token",
      "code": 403
    }
    
  • 404 Not Found

    The notebook no longer exists at Google, or the account it names is not configured. In sync mode, a run that disappeared from the notebook while it ran also answers 404 with the failed job record (error.code: "not_found").

    {
      "error": "Account [email protected] of user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55 is not configured",
      "code": 404
    }
    
  • 409 Conflict

    Sync mode, the run was cancelled within the 90-second wait, with DELETE /jobs/jobid or in the Gemini Notebook web app. The body is the failed job record with error.code: "cancelled".

  • 422 Unprocessable Content

    Sync mode, Google ended the run within 90 seconds in a state the API does not recognise. The body is the failed job record with error.code: "generation_failed".

  • 429 Too Many Requests

    The account already runs maxJobs jobs. Retry when one finishes, or raise maxJobs with POST /accounts:

    {
      "error": "Account [email protected] is busy: 2/2 jobs running (maxJobs)",
      "code": 429
    }
    

    Google refused the run because not enough of its usage window is left. No job was created. retryAt and window are present when Google’s refusal names the window:

    {
      "error": "Not enough of Google's 5h window is left on account [email protected] for this job; it resets at 2026-09-29T07:40:48.000Z. GET /accounts/[email protected] shows what each job needs",
      "code": 429,
      "retryAt": "2026-09-29T07:40:48.000Z",
      "window": "5h"
    }
    
  • 503 Service Unavailable

    A temporary condition, retry in a few minutes. A 502 means Google answered with an unexpected error.

    {
      "error": "Async mode is unavailable right now, use mode sync",
      "code": 503
    }
    

    The job could not be added to our job schedule. It is failed at once with error.code: "scheduler". Google had already started the run by then, and it is not stopped.

    {
      "error": "Unable to lock the job schedule of user 12345, please retry",
      "code": 503
    }
    
  • 596 Account Error

    Google reported the account as signed out. While we re-check it, the answer is the first message below. Retry in about a minute. If it stays signed out, the account is paused, you receive an email, and the answer becomes the second message until you re-add it via Setup Gemini Notebook.

    {
      "error": "Google reported this account as signed out. We are re-checking it — please retry in about a minute. If it stays signed out, you will receive a re-add email.",
      "code": 596
    }
    
    {
      "error": "Account [email protected]: Google signed this account out. Re-add it at https://useapi.net/docs/start-here/setup-gemini-notebook",
      "code": 596
    }
    
Model

The job record. GET /jobs/jobid and the replyUrl webhook return the same shape. A research job has type: "research" and no artifact. The type you sent (fast or deep) is echoed in request.type and in result.mode.

In sync mode a failed job answers with an HTTP status that matches error.code: quota → 429, account → 596, not_found → 404, generation_failed → 422, cancelled → 409, timeout → 504, anything else → 502.

{ // TypeScript, all fields are optional
  jobid: string                  // job:<uuid>-user:<id>-<email>-bot:gemini_notebook
  email: string                  // the account the job runs on
  type: 'research'
  status: 'processing' | 'completed' | 'failed'
  notebook: string
  created_at: string             // ISO 8601
  completed_at?: string          // ISO 8601, when the job completed or failed
  request: {                     // your request body echoed back, without mode, replyUrl and replyRef
    notebook: string
    query: string
    type?: 'fast' | 'deep'
    source?: 'web' | 'drive'
  }
  replyUrl?: string
  replyRef?: string
  error?: {                      // status 'failed'
    code: 'quota' | 'account' | 'not_found' | 'generation_failed' | 'timeout' | 'google_error' | 'scheduler' | 'cancelled'
    message: string
    retryAt?: string
  }
  result?: {                     // status 'completed'
    mode: 'fast' | 'deep'
    query: string
    summary?: string             // fast: Google's one-line summary of what it found
    report?: {                   // deep: the Deep Research report
      title: string
      markdown: string
    }
    noResults?: true             // the run found nothing (sources is [])
    sources: {                   // [] when the run found nothing
      url: string
      title: string
      description: string | null
      cited: boolean             // deep: the report cites it. fast: always true
      driveFileId?: string       // source drive: the Drive file id
      mimeType?: string | null   // source drive: the file's type, null when Google's type code is not one we know yet
    }[]
  }
}
Examples
  • curl -X POST "https://api.useapi.net/v1/gemini-notebook/research" \
       -H "Content-Type: application/json" \
       -H "Authorization: Bearer …" \
       -d '{
         "notebook": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
         "query": "Apollo 11 lunar module guidance computer alarms"
       }'
    
  • const token = "API token";
    const apiUrl = "https://api.useapi.net/v1/gemini-notebook";
    const headers = { "Content-Type": "application/json", "Authorization": `Bearer ${token}` };
    
    const response = await fetch(`${apiUrl}/research`, {
      method: "POST",
      headers,
      body: JSON.stringify({
        notebook: "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
        query: "Why did the Apollo 11 landing nearly abort?",
        type: "deep",
        mode: "async"
      })
    });
    let job = await response.json();
    console.log("submitted", response.status, job);
    
    while (job.status === "pending" || job.status === "processing") {
      await new Promise(r => setTimeout(r, 15000));
      job = await (await fetch(`${apiUrl}/jobs/${encodeURIComponent(job.jobid)}`, { headers })).json();
      console.log(job.status);
    }
    console.log("result", job.result ?? job.error);
    
  • import time
    import requests
    from urllib.parse import quote
    
    token = "API token"
    apiUrl = "https://api.useapi.net/v1/gemini-notebook"
    headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"}
    
    data = {
        "notebook": "user:[email protected]:d02c903b-17f8-4241-a263-2be9e7359d55",
        "query": "Why did the Apollo 11 landing nearly abort?",
        "type": "deep",
        "mode": "async"
    }
    response = requests.post(f"{apiUrl}/research", headers=headers, json=data)
    job = response.json()
    print("submitted", response.status_code, job)
    
    while job.get("status") in ("pending", "processing"):
        time.sleep(15)
        job = requests.get(f"{apiUrl}/jobs/{quote(job['jobid'], safe='')}", headers=headers).json()
        print(job["status"])
    
    print("result", job.get("result") or job.get("error"))
    
Try It