Research sources
September 29, 2026
Table of contents
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-linesummaryof what it found. In our tests it returned 10 sources in about 15 seconds.deepis 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 returns200with itsresult, which is the usual outcome forfast. A run still going at 90 seconds returns202with the job record, the usual outcome fordeep, 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"returns201with 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". replyUrlreceives onePOSTof 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
API tokenis required, see Setup useapi.net for details.
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"
}
notebookis required, the notebook id returned by POST /notebooks or GET /notebooks. The id names its account, so the job runs there.queryis required, what to research.
Length:1to2,000characters.typeis optional, the kind of research.
Supported values:fast(Discover sources, default),deep(Deep Research).sourceis optional, where to search.
Supported values:web(default),drive(the account’s Google Drive,type: "fast"only).drivewithtype: "deep"returns400.modeis optional,sync(default) orasync. See Sync, async and webhooks.replyUrlis optional, a publichttp(s)URL that receives onePOSTof the job record when the job completes or fails. See GET /jobs/jobidfor the record’s shape.replyRefis optional, your own reference echoed back in the job record, up to 1024 characters.
Responses
-
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/
jobidor 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 } ] } } -
Async mode. The job is created and returned at once. Poll GET /jobs/
jobiduntilstatusiscompletedorfailed.{ "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" } -
Sync mode, still running after 90 seconds. Poll GET /jobs/
jobidfor the result. The job record is the same as the201one. -
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 } -
Invalid API token.
{ "error": "useapi.net ⁝ Unauthorized", "code": 401 } -
The
notebookid 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 } -
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
404with 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 } -
Sync mode, the run was cancelled within the 90-second wait, with DELETE /jobs/
jobidor in the Gemini Notebook web app. The body is the failed job record witherror.code: "cancelled". -
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". -
The account already runs
maxJobsjobs. Retry when one finishes, or raisemaxJobswith 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.
retryAtandwindoware 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" } -
A temporary condition, retry in a few minutes. A
502means 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"))