Skip to main content

NotebookLM REST API reference — 45 HTTP endpoints

Coverage. All 45 endpoints the server exposes are documented below, and the OpenAPI 3.1 spec carries the same 45 — both checked against the routes declared in the code.

Complete reference for the NotebookLM HTTP REST API. Citation-backed Q&A, Studio content generation, notebook library, multi-account, sessions.

OpenAPI 3.1 spec: openapi.yaml (importable in Postman, Insomnia, Bruno, Swagger UI). Source in the repo at deployment/docs/openapi.yaml.

Companion guides: REST batch pattern (1 000 questions overnight) · n8n integration · Multi-account rotation · Compare with PleasePrompto/notebooklm-mcp v2.0.0


🌐 Base URL​

http://localhost:3000

Or for network access: http://<SERVER-IP>:3000


Available Endpoints (45 total)​

Authentication​

MethodEndpointDescription
POST/setup-authFirst-time authentication
POST/de-authLogout (clear credentials)
POST/re-authRe-authenticate / switch account
POST/cleanup-dataClean all data (requires confirm)

Queries​

MethodEndpointDescription
GET/Server identity, version, docs link
GET/healthServer health check
POST/askAsk a question to NotebookLM
POST/batch-to-vaultRun many questions, write each answer to the vault

Notebooks​

MethodEndpointDescription
GET/notebooksList all notebooks
POST/notebooksAdd a notebook manually
POST/notebooks/createCreate a new notebook in NotebookLM
POST/notebooks/auto-discoverAuto-generate notebook metadata
GET/notebooks/scrapeScrape notebooks from NotebookLM
POST/notebooks/import-from-scrapeBulk import scraped notebooks
GET/notebooks/searchSearch notebooks by query
GET/notebooks/statsGet library statistics
GET/notebooks/:idGet notebook details
PUT/notebooks/:idUpdate notebook metadata
DELETE/notebooks/:idDelete a notebook
DELETE/notebooks/bulk-deleteDelete several notebooks in one call
PUT/notebooks/:id/activateActivate a notebook (set as default)
GET/notebooks/:id/shareRead sharing status
PUT/notebooks/:id/shareToggle the public link
GET/notebooks/:id/labelsList source labels
POST/notebooks/:id/labelsCreate or delete source labels

Sessions​

MethodEndpointDescription
GET/sessionsList active sessions
POST/sessions/:id/resetReset session history
DELETE/sessions/:idClose a session

Content Management​

MethodEndpointDescription
POST/content/sourcesAdd source/document to notebook
DELETE/content/sources/:idDelete source by ID
DELETE/content/sourcesDelete source by name (query param)
POST/content/generateGenerate content (audio, video, report, etc.)
GET/content/downloadDownload/export content
POST/content/notesCreate a note in the notebook
POST/content/chat-to-noteSave chat discussion to a note
POST/content/notes/:noteTitle/to-sourceConvert note to source
GET/contentList sources and generated content
DELETE/content/:contentIdDelete a generated Studio artifact
GET/notebooks/:id/sourcesList a notebook's sources with their IDs
GET/notebooks/:id/sources/:sourceIdRead a source's full indexed text
POST/content/notes/listList the notebook's notes
POST/content/notes/getRead one note, by title or ID
POST/content/study-aidGenerate flashcards or a quiz
POST/content/mind-mapGenerate and save a mind map
POST/content/researchDiscover web sources (Fast Research)

Note: v1.5.0 consolidated content generation into /content/generate with all NotebookLM Studio features (audio_overview, video, infographic, report, presentation, data_table).


0. API Root​

GET /​

Returns the server's identity, its version and a short, hand-maintained list of entry points.

Unlike /health, this route is not exempt from the token guard: when NOTEBOOKLM_API_KEY is set, an unauthenticated call is rejected rather than answered with a reduced payload.

Request:

curl http://localhost:3000/

Success Response (200):

{
"name": "NotebookLM MCP HTTP Server",
"version": "4.0.0",
"endpoints": {
"health": "GET /health",
"ask": "POST /ask",
"batch_to_vault": "POST /batch-to-vault",
"setup_auth": "POST /setup-auth",
"notebooks": "GET /notebooks",
"sources": "GET /notebooks/:id/sources",
"read_source": "GET /notebooks/:id/sources/:sourceId",
"sessions": "GET /sessions"
},
"docs": "https://notebooklm.roomi-fields.com/"
}

Note the response shape: this is the only route that does not wrap its payload in { "success": ..., "data": ... }. The endpoints map is a fixed excerpt of eight routes, not a discovery mechanism — the full list is the table at the top of this page and openapi.yaml. The version field is read from package.json at startup, so it is correct however the server was launched.


1. Health Check​

GET /health​

Check server and authentication status.

Request:

curl http://localhost:3000/health

Success Response (200):

{
"success": true,
"data": {
"authenticated": true,
"sessions": 2,
"library_notebooks": 3,
"context_age_hours": 0.25
}
}

Error Response (500):

{
"success": false,
"error": "Error message here"
}

Fields:

  • authenticated - Valid Google session
  • sessions - Number of active sessions
  • library_notebooks - Number of configured notebooks
  • context_age_hours - Browser context age (hours)

2. Ask Question​

POST /ask​

Ask a question to NotebookLM and get a response.

Request:

curl -X POST http://localhost:3000/ask \
-H "Content-Type: application/json" \
-d '{
"question": "What are the main tips for parents?",
"notebook_id": "parents-numerique"
}'

Body Parameters:

ParameterTypeRequiredDescription
questionstring✅ YesThe question to ask
notebook_idstring❌ NoNotebook ID (or URL)
notebook_urlstring❌ NoDirect notebook URL
session_idstring❌ NoReuse an existing session
show_browserboolean❌ NoShow Chrome (debug)
source_formatstring❌ NoCitation extraction format (see below)

Source Format Options:

FormatDescriptionExample Output
noneNo extraction (default, fastest)"text[1]..."
inlineInsert source text inline"text[1: "source excerpt..."]..."
footnotesAppend sources at the endAnswer + ---\n**Sources:**\n[1] text...
jsonReturn sources as separate object{ answer: "...", sources: { citations } }
expandedReplace markers with full quoted text"text "full source quote..."..."

Success Response (200):

{
"success": true,
"data": {
"status": "success",
"question": "What advice for parents in the digital age?",
"answer": "Empathy is a fundamental concept...",
"session_id": "9a580eee",
"notebook_url": "https://notebooklm.google.com/notebook/xxx",
"session_info": {
"age_seconds": 44,
"message_count": 1,
"last_activity": 1763737756057
}
}
}

Success Response with Sources (200):

When using source_format other than none:

{
"success": true,
"data": {
"status": "success",
"question": "What is the main topic?",
"answer": "The Self is the core essence[1: \"The Self is the seat of consciousness...\"]...",
"session_id": "abc123",
"notebook_url": "https://notebooklm.google.com/notebook/xxx",
"session_info": { ... },
"sources": {
"format": "inline",
"citations": [
{
"marker": "[1]",
"number": 1,
"sourceText": "The Self is the seat of consciousness that possesses the 8 C's..."
}
],
"extraction_success": true
}
}
}

Error Response (400):

{
"success": false,
"error": "Missing required field: question"
}

Error Response (500):

{
"success": false,
"error": "Timeout waiting for response from NotebookLM"
}

Response Time: 30-60 seconds

PowerShell Examples:

# Simple question
$body = @{
question = "What are the main tips for parents?"
notebook_id = "parents-numerique"
} | ConvertTo-Json

Invoke-RestMethod -Uri "http://localhost:3000/ask" -Method Post -Body $body -ContentType "application/json"

# With existing session
$body = @{
question = "Follow-up question"
session_id = "9a580eee"
} | ConvertTo-Json

Invoke-RestMethod -Uri "http://localhost:3000/ask" -Method Post -Body $body -ContentType "application/json"

2b. Batch Questions to Vault​

POST /batch-to-vault​

Run a list of questions against one notebook and write each answer to disk as a markdown file plus a JSON sidecar, ready for indexing by RTFM or any other markdown vault tool. Questions run sequentially and reuse the same session, so each answer has the context of the previous ones.

Request:

curl -X POST http://localhost:3000/batch-to-vault \
-H "Content-Type: application/json" \
-d '{
"questions": [
"What is the central claim of the book?",
"Which objections does the author anticipate?"
],
"vault_dir": "/home/user/vault/nblm",
"notebook_id": "ifs-therapy",
"slug_prefix": "ifs",
"sleep_between_ms": 2000
}'

Body Parameters:

ParameterTypeRequiredDescription
questionsstring[]✅ YesNon-empty list of questions, asked in order
vault_dirstring✅ YesOutput directory, created if missing
notebook_idstring❌ NoLibrary notebook to query
notebook_urlstring❌ NoNotebook URL, used instead of notebook_id
slug_prefixstring❌ NoPrefix for every filename (default: none)
source_formatstring❌ Nonone, inline, footnotes, json, expanded (default: json)
sleep_between_msnumber❌ NoPause between questions, in milliseconds (default: 0)
session_idstring❌ NoReuse an existing session instead of opening a new one

Neither notebook_id nor notebook_url is required: without them the active notebook is used.

File naming. Each answer is written as {slug}.md and {slug}.json, where the slug is a three-digit index followed by a slugified question, optionally prefixed — ifs-001-what-is-the-.... Path separators and .. sequences are stripped from slug_prefix, and it is truncated to 64 characters, so it can only ever contribute a filename component.

Containment. When NOTEBOOKLM_VAULT_ROOT is set, vault_dir must resolve inside it, and the call fails otherwise. When the variable is unset, any writable path is accepted.

Success Response (200):

{
"success": true,
"data": {
"vault_dir": "/home/user/vault/nblm",
"total": 2,
"succeeded": 2,
"failed": 0,
"session_id": "9a580eee",
"notebook": {
"id": "ifs-therapy",
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101"
},
"files": [
{
"question": "What is the central claim of the book?",
"md_path": "/home/user/vault/nblm/ifs-001-what-is-the-central-claim-of-the-book.md",
"json_path": "/home/user/vault/nblm/ifs-001-what-is-the-central-claim-of-the-book.json",
"success": true,
"citations_count": 7
}
]
}
}

A question that fails does not abort the batch: it is recorded in files with success: false, an error message and empty paths, and the run continues. The notebook.name field is only present when the answer carried one.

Error Response (400):

{
"success": false,
"error": "Missing required field: vault_dir (absolute or relative directory path)"
}

A missing or empty questions array returns 400 in the same shape. A run that throws — an unwritable directory, for instance — returns the error with status 400 as well, since the handler maps any unsuccessful result to 400.

Response Time: 30–60 seconds per question, plus sleep_between_ms between them.


3. Setup Auth​

POST /setup-auth​

Configure Google authentication (opens Chrome).

Request:

curl -X POST http://localhost:3000/setup-auth \
-H "Content-Type: application/json" \
-d '{
"show_browser": true
}'

Body Parameters:

ParameterTypeRequiredDescription
show_browserboolean❌ NoShow Chrome (default: true)

Success Response (200):

{
"success": true,
"data": {
"status": "success",
"message": "Authentication setup completed successfully"
}
}

4. List Notebooks​

GET /notebooks​

List all notebooks configured in the library.

Request:

curl http://localhost:3000/notebooks

Success Response (200):

{
"success": true,
"data": {
"notebooks": [
{
"id": "parents-numerique",
"name": "Parents and Digital",
"description": "Advice for parents in the digital age",
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101",
"topics": ["parenting", "digital", "education"],
"use_cases": [
"Educational advice in the digital age",
"Questions about parenting and screens"
],
"active": true
}
],
"count": 1
}
}

5. Add Notebook​

POST /notebooks​

Add a new notebook to the library.

⚠️ Automatic validations:

  • ✅ Checks NotebookLM URL format
  • ✅ Validates that the notebook actually exists (live check)
  • ✅ Blocks duplicate names
  • ✅ Creates a temporary session to test access

Request:

curl -X POST http://localhost:3000/notebooks \
-H "Content-Type: application/json" \
-d '{
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101",
"name": "Parents and Digital",
"description": "Advice for parents in the digital age",
"topics": ["parenting", "digital", "education"]
}'

Body Parameters:

ParameterTypeRequiredDescription
urlstring✅ YesNotebookLM notebook URL
namestring✅ YesNotebook name (unique)
descriptionstring✅ YesDescription
topicsstring[]✅ YesList of topics
content_typesstring[]❌ NoContent types (default: ["documentation", "examples"])
use_casesstring[]❌ NoUse cases (auto-generated if absent)
tagsstring[]❌ NoTags

Success Response (200):

{
"success": true,
"data": {
"notebook": {
"id": "parents-numerique",
"name": "Parents and Digital",
"description": "Advice for parents in the digital age",
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101",
"topics": ["parenting", "digital", "education"],
"content_types": ["documentation", "examples"],
"use_cases": ["Educational advice", "Digital parenting"],
"added_at": "2025-11-22T08:49:16.735Z",
"last_used": "2025-11-22T08:49:16.735Z",
"use_count": 0,
"tags": [],
"active": false
}
}
}

Possible Errors:

400 - Name already in use:

{
"success": false,
"error": "A notebook with the name 'Parents and Digital' already exists.\n\nExisting notebook ID: parents-numerique\nURL: https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101\n\nPlease use a different name, or update the existing notebook instead.\nTo update: PUT /notebooks/parents-numerique with new data\nTo delete: DELETE /notebooks/parents-numerique"
}

400 - Invalid URL:

{
"success": false,
"error": "Invalid NotebookLM URL: https://example.com\n\nExpected format: https://notebooklm.google.com/notebook/[notebook-id]\n\nExample: https://notebooklm.google.com/notebook/abc-123-def-456\n\nTo get the URL:\n1. Go to https://notebooklm.google.com\n2. Open your notebook\n3. Copy the URL from the address bar"
}

400 - Notebook inaccessible:

{
"success": false,
"error": "Invalid or inaccessible notebook.\n\nURL: https://notebooklm.google.com/notebook/invalid-id\n\nThe notebook page loaded but the chat interface was not found.\nThis usually means:\n- The notebook doesn't exist\n- You don't have access to this notebook\n- The notebook ID in the URL is incorrect\n\nPlease verify the URL by:\n1. Go to https://notebooklm.google.com\n2. Open the notebook manually\n3. Copy the exact URL from the address bar"
}

⏱️ Response Time: 15-30 seconds (live validation)


6. Auto-Discover Notebook​

POST /notebooks/auto-discover​

Automatically generate notebook metadata by querying NotebookLM itself.

Request:

{
"url": "https://notebooklm.google.com/notebook/abc123"
}

Response (Success):

{
"success": true,
"notebook": {
"id": "generated-uuid",
"url": "https://notebooklm.google.com/notebook/abc123",
"name": "auto-generated-notebook",
"description": "Comprehensive guide covering key concepts. Includes practical exercises and examples.",
"tags": ["topic1", "topic2", "learning", "examples", "exercises"],
"auto_generated": true,
"created_at": "2025-01-23T10:00:00Z"
},
"message": "Notebook auto-discovered and added to library"
}

Response (Error):

{
"error": "NotebookLM returned invalid metadata format",
"details": "Invalid name format: \"Invalid Name\". Must be kebab-case, 3 words max."
}

Errors:

  • 400 Bad Request: Invalid URL format
  • 404 Not Found: Notebook not accessible
  • 500 Internal Server Error: NotebookLM query failed or returned invalid format
  • 504 Gateway Timeout: NotebookLM query timeout (>30s)

How it works:

  1. System opens the specified notebook
  2. Sends prompt to NotebookLM asking it to analyze its own content
  3. NotebookLM responds with JSON containing name, description, and tags
  4. System validates the metadata format
  5. Saves notebook to library with auto-generated metadata

Progressive Disclosure Pattern:

This endpoint enables the Level 0 of progressive disclosure:

  • Metadata stored locally (lightweight, ~100 bytes per notebook)
  • Loaded at startup for instant matching
  • Deep queries to NotebookLM only when notebook is selected

Orchestrators (Claude Code, n8n, Cursor) can scan all notebook metadata without rate limit concerns, then query NotebookLM only for the most relevant notebook.


6b. Create Notebook​

POST /notebooks/create​

Create a new empty notebook directly in NotebookLM.

Request:

curl -X POST http://localhost:3000/notebooks/create \
-H "Content-Type: application/json" \
-d '{
"name": "My New Notebook"
}'

Body Parameters:

ParameterTypeRequiredDescription
namestring❌ NoNotebook name (auto-generated if not provided)
show_browserboolean❌ NoShow browser during creation

Success Response (200):

{
"success": true,
"data": {
"notebook_url": "https://notebooklm.google.com/notebook/abc123-def456",
"name": "My New Notebook"
}
}

Note: This creates the notebook in NotebookLM but does NOT add it to the local library. Use POST /notebooks or POST /notebooks/auto-discover to add it to the library after creation.


7. Get Notebook​

GET /notebooks/:id​

Get details of a specific notebook.

Request:

curl http://localhost:3000/notebooks/parents-numerique

Success Response (200):

{
"success": true,
"data": {
"notebook": {
"id": "parents-numerique",
"name": "Parents and Digital",
"description": "Advice for parents in the digital age",
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000101",
"topics": ["parenting", "digital", "education"],
"active": true
}
}
}

Error Response (404):

{
"success": false,
"error": "Notebook not found: parents-numerique"
}

8. Delete Notebook​

DELETE /notebooks/:id​

Delete a notebook from the library.

Request:

curl -X DELETE http://localhost:3000/notebooks/parents-numerique

Success Response (200):

{
"success": true,
"data": {
"message": "Notebook removed successfully",
"id": "parents-numerique"
}
}

Error Response (404):

{
"success": false,
"error": "Notebook not found: parents-numerique"
}

Behavior:

  • If the deleted notebook was active, the first remaining notebook automatically becomes active
  • If it was the last notebook, active_notebook_id becomes null
  • Sessions using this notebook remain open but are no longer linked to a library notebook

8b. Bulk Delete Notebooks​

DELETE /notebooks/bulk-delete​

Delete several notebooks from NotebookLM itself, by UUID. This removes the notebooks from your Google account; it is not the same as DELETE /notebooks/:id, which only drops an entry from the local library.

Each deletion is verified against a fresh listing afterwards, so a notebook that is still present is reported in failed rather than falsely claimed as deleted.

Request:

curl -X DELETE http://localhost:3000/notebooks/bulk-delete \
-H "Content-Type: application/json" \
-d '{
"notebook_ids": [
"74912e55-34a4-4027-bdcc-8e89badd0efd",
"c3ae2b1b-b362-46ae-9dc8-7b658a05955e"
]
}'

Body Parameters:

ParameterTypeRequiredDescription
notebook_idsstring[]✅ YesNon-empty list of NotebookLM notebook UUIDs
show_browserboolean❌ NoShow Chrome during the fallback browser flow (default: false)

show_browser only has an effect if the RPC path fails and the browser fallback runs; the RPC path never opens a window.

Success Response (200):

{
"success": true,
"data": {
"deleted": ["74912e55-34a4-4027-bdcc-8e89badd0efd"],
"failed": ["c3ae2b1b-b362-46ae-9dc8-7b658a05955e"],
"message": "Deleted 1 notebooks, 1 failed"
}
}

The envelope stays success: true even when some or all of the IDs are in failed — read the two arrays, not the flag.

Error Response (400):

{
"success": false,
"error": "notebook_ids array is required"
}

9. Activate Notebook​

PUT /notebooks/:id/activate​

Set a notebook as active (default notebook for requests without notebook_id).

Request:

curl -X PUT http://localhost:3000/notebooks/shakespeare/activate

Success Response (200):

{
"success": true,
"data": {
"message": "Notebook activated successfully",
"notebook": {
"id": "shakespeare",
"name": "Shakespeare",
"description": "William Shakespeare - Complete Works",
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000102",
"topics": ["literature", "theater", "Shakespeare"],
"active": true,
"last_used": "2025-11-22T10:30:45.123Z"
}
}
}

Error Response (404):

{
"success": false,
"error": "Notebook not found: shakespeare"
}

Behavior:

  • Updates last_used to current date/time
  • Sets active_notebook_id in library.json
  • Does not create a session (metadata only)

9b. Notebook Sharing​

GET /notebooks/:id/share​

Read a notebook's sharing status: whether the public link is on, the link itself, and the list of collaborators.

Path Parameters:

ParameterTypeRequiredDescription
idstring✅ YesNotebookLM notebook UUID

Request:

curl http://localhost:3000/notebooks/74912e55-34a4-4027-bdcc-8e89badd0efd/share

Success Response (200):

{
"success": true,
"data": {
"isPublic": true,
"publicLink": "https://notebooklm.google.com/notebook/74912e55-34a4-4027-bdcc-8e89badd0efd",
"collaborators": [{ "email": "colleague@example.com", "name": "A. Colleague" }]
}
}

publicLink is absent when the notebook is restricted, and a collaborator's name is absent when NotebookLM does not return one.

PUT /notebooks/:id/share​

Turn the public link on or off. The response is the resulting status, read back after the change, in the same shape as the GET.

Request:

curl -X PUT http://localhost:3000/notebooks/74912e55-34a4-4027-bdcc-8e89badd0efd/share \
-H "Content-Type: application/json" \
-d '{ "public": true }'

Body Parameters:

ParameterTypeRequiredDescription
publicboolean✅ Yestrue enables the public link

Strictly speaking the handler accepts a call without a body, but only the literal value true enables the link: any other value, including a missing body, is read as false and turns sharing off. Always send the field explicitly.

Success Response (200):

{
"success": true,
"data": {
"isPublic": true,
"publicLink": "https://notebooklm.google.com/notebook/74912e55-34a4-4027-bdcc-8e89badd0efd",
"collaborators": []
}
}

9c. Source Labels​

Labels group a notebook's sources. Both routes return the notebook's full label list, so the POST doubles as a read-after-write.

GET /notebooks/:id/labels​

List the labels defined on a notebook.

Path Parameters:

ParameterTypeRequiredDescription
idstring✅ YesNotebookLM notebook UUID

Request:

curl http://localhost:3000/notebooks/74912e55-34a4-4027-bdcc-8e89badd0efd/labels

Success Response (200):

{
"success": true,
"data": {
"labels": [
{
"id": "7f1c2d90-8b44-4a31-9a6e-5c0d2e8f1a33",
"name": "Primary sources",
"emoji": "📚",
"sourceCount": 12
},
{ "id": "a2b9e114-6d02-4c88-bf31-9e7a4c105d21", "name": "To review", "sourceCount": 0 }
]
}
}

emoji is absent when the label has none.

POST /notebooks/:id/labels​

Create or delete labels.

Request:

curl -X POST http://localhost:3000/notebooks/74912e55-34a4-4027-bdcc-8e89badd0efd/labels \
-H "Content-Type: application/json" \
-d '{
"action": "create",
"name": "Primary sources",
"emoji": "📚"
}'

Body Parameters:

ParameterTypeRequiredDescription
actionstring❌ Nolist, create or delete (default: list)
namestring❌ NoLabel name. Required when action is create
emojistring❌ NoEmoji shown beside the label (default: none)
label_idsstring[]❌ NoLabels to remove. Required when action is delete

Success Response (200): same shape as the GET — the label list after the change.

Error Response (200 with success: false):

{
"success": false,
"error": "name required to create a label"
}

A delete without label_ids returns label_ids required to delete in the same form. Note the status code: these validation failures are carried in the body, not in the HTTP status, and the route only returns 500 when the underlying call throws.


10. List Sessions​

GET /sessions​

List all active browser sessions.

Request:

curl http://localhost:3000/sessions

Success Response (200):

{
"success": true,
"data": {
"sessions": [
{
"id": "session-00000001",
"notebook_url": "https://notebooklm.google.com/notebook/xxx",
"message_count": 3,
"age_seconds": 245,
"inactive_seconds": 120,
"last_activity": 1763737756057
}
],
"count": 1,
"max_sessions": 10
}
}

11. Close Session​

DELETE /sessions/:id​

Close a specific browser session.

Request:

curl -X DELETE http://localhost:3000/sessions/9a580eee

Success Response (200):

{
"success": true,
"data": {
"message": "Session closed successfully",
"session_id": "9a580eee"
}
}

Error Response (404):

{
"success": false,
"error": "Session not found: 9a580eee"
}

12. De-authenticate (Logout)​

POST /de-auth​

Logout by clearing all authentication data. Preserves notebook library.

Request:

curl -X POST http://localhost:3000/de-auth

Success Response (200):

{
"success": true,
"data": {
"status": "de-authenticated",
"message": "Successfully logged out. Use setup_auth or re_auth to authenticate again.",
"authenticated": false
}
}

Use cases:

  • Security logout before shutting down
  • Clearing credentials without re-authenticating
  • Removing access temporarily

13. Re-authenticate​

POST /re-auth​

Switch to a different Google account or re-authenticate after logout.

Request:

curl -X POST http://localhost:3000/re-auth \
-H "Content-Type: application/json" \
-d '{
"show_browser": true
}'

Body Parameters:

ParameterTypeRequiredDescription
show_browserboolean❌ NoShow browser window (default: true)

Success Response (200):

{
"success": true,
"data": {
"status": "authenticated",
"message": "Successfully re-authenticated",
"authenticated": true,
"duration_seconds": 45.2
}
}

Use cases:

  • Switching Google accounts
  • Recovery from rate limits (50 queries/day on free accounts)
  • Fresh authentication after errors

14. Cleanup Data​

POST /cleanup-data​

Deep cleanup of all NotebookLM MCP data files across 8 categories.

⚠️ CRITICAL: Close ALL Chrome/Chromium instances BEFORE running this!

Request:

# Preview first (confirm=false)
curl -X POST http://localhost:3000/cleanup-data \
-H "Content-Type: application/json" \
-d '{
"confirm": false,
"preserve_library": true
}'

# Execute cleanup (confirm=true)
curl -X POST http://localhost:3000/cleanup-data \
-H "Content-Type: application/json" \
-d '{
"confirm": true,
"preserve_library": true
}'

Body Parameters:

ParameterTypeRequiredDescription
confirmboolean✅ YesMust be true to execute (false for preview)
preserve_libraryboolean❌ NoKeep library.json file (default: false)

Success Response (200):

{
"success": true,
"data": {
"message": "Cleanup completed successfully",
"files_deleted": 47,
"space_freed_mb": 156.8,
"library_preserved": true
}
}

15. Update Notebook​

PUT /notebooks/:id​

Update notebook metadata (name, description, topics, etc.).

Request:

curl -X PUT http://localhost:3000/notebooks/n8n-workflows \
-H "Content-Type: application/json" \
-d '{
"name": "n8n Advanced Workflows",
"description": "Advanced n8n workflow patterns and best practices",
"topics": ["n8n", "automation", "workflows", "advanced"]
}'

Body Parameters:

ParameterTypeRequiredDescription
namestring❌ NoNew notebook name
descriptionstring❌ NoNew description
topicsstring[]❌ NoNew topics array
use_casesstring[]❌ NoNew use cases array

Success Response (200):

{
"success": true,
"data": {
"notebook": {
"id": "n8n-workflows",
"name": "n8n Advanced Workflows",
"description": "Advanced n8n workflow patterns and best practices",
"topics": ["n8n", "automation", "workflows", "advanced"],
"last_modified": "2025-01-24T12:00:00.000Z"
}
}
}

16. Search Notebooks​

GET /notebooks/search?query=keyword​

Search notebooks by keyword in name, description, or topics.

Request:

curl "http://localhost:3000/notebooks/search?query=automation"

Query Parameters:

ParameterTypeRequiredDescription
querystring✅ YesSearch keyword

Success Response (200):

{
"success": true,
"data": {
"notebooks": [
{
"id": "n8n-workflows",
"name": "n8n Advanced Workflows",
"description": "Advanced n8n workflow patterns",
"topics": ["n8n", "automation", "workflows"],
"score": 0.95
}
]
}
}

17. Get Library Stats​

GET /notebooks/stats​

Get statistics about the notebook library.

Request:

curl http://localhost:3000/notebooks/stats

Success Response (200):

{
"success": true,
"data": {
"total_notebooks": 5,
"active_notebook_id": "n8n-workflows",
"total_queries": 127,
"most_used_notebook": {
"id": "n8n-workflows",
"name": "n8n Advanced Workflows",
"use_count": 45
},
"recently_added": [
{
"id": "llm-dev",
"name": "LLM Development",
"added_at": "2025-01-24T10:00:00.000Z"
}
]
}
}

18. Reset Session​

POST /sessions/:id/reset​

Reset a session's chat history while keeping the same session ID.

Request:

curl -X POST http://localhost:3000/sessions/9a580eee/reset

Success Response (200):

{
"success": true,
"data": {
"message": "Session reset successfully",
"session_id": "9a580eee",
"previous_message_count": 12
}
}

Use cases:

  • Clean slate for new task without losing session context
  • Starting fresh conversation in same notebook

🔒 HTTP Error Codes​

CodeMeaningDescription
200OKSuccessful request
400Bad RequestMissing or invalid parameters
401UnauthorizedAuthentication required (if API key enabled)
404Not FoundResource not found
500Internal Server ErrorServer error
503Service UnavailableServer overloaded (too many sessions)

15. Add Source to Notebook​

POST /content/sources​

Add a document/source to a notebook. Supports multiple source types.

Request:

# Add URL source
curl -X POST http://localhost:3000/content/sources \
-H "Content-Type: application/json" \
-d '{
"source_type": "url",
"url": "https://example.com/article",
"notebook_url": "https://notebooklm.google.com/notebook/abc123"
}'

# Add text content
curl -X POST http://localhost:3000/content/sources \
-H "Content-Type: application/json" \
-d '{
"source_type": "text",
"text": "Your document content here...",
"title": "My Document"
}'

# Add YouTube video
curl -X POST http://localhost:3000/content/sources \
-H "Content-Type: application/json" \
-d '{
"source_type": "youtube",
"url": "https://www.youtube.com/watch?v=VIDEO_ID"
}'

Body Parameters:

ParameterTypeRequiredDescription
source_typestring✅ YesType: file, url, text, youtube, google_drive
file_pathstring❌ NoLocal file path (for file type)
urlstring❌ NoURL (for url, youtube, google_drive types)
textstring❌ NoText content (for text type)
titlestring❌ NoOptional title for the source
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse existing session

Success Response (200):

{
"success": true,
"sourceName": "My Document",
"status": "ready"
}

15b. Delete Source from Notebook​

DELETE /content/sources/:id​

Delete a source from a notebook by its ID.

Request:

curl -X DELETE "http://localhost:3000/content/sources/source-123?notebook_url=https://notebooklm.google.com/notebook/abc123"

Path Parameters:

ParameterTypeRequiredDescription
idstringYesThe unique ID of the source

Query Parameters:

ParameterTypeRequiredDescription
notebook_urlstringNoTarget notebook URL
session_idstringNoReuse existing session

Success Response (200):

{
"success": true,
"data": {
"success": true,
"sourceId": "source-123",
"sourceName": "My Document"
}
}

Error Response (404):

{
"success": false,
"error": "Source not found: source-123"
}

DELETE /content/sources (Alternative)​

Delete a source by name using query parameters. Useful when you know the source name but not the ID.

Request:

curl -X DELETE "http://localhost:3000/content/sources?source_name=My%20Document"

Query Parameters:

ParameterTypeRequiredDescription
source_idstringNo*The unique ID of the source
source_namestringNo*The name of the source (partial match)
notebook_urlstringNoTarget notebook URL
session_idstringNoReuse existing session

*At least one of source_id or source_name is required.

Success Response (200):

{
"success": true,
"data": {
"success": true,
"sourceId": "source-123",
"sourceName": "My Document"
}
}

Notes:

  • The source_name parameter supports partial matching (case-insensitive)
  • Use list_content first to find source IDs and names
  • This action is irreversible - the source will be permanently removed

16. Generate Content​

POST /content/generate​

Generate content using NotebookLM Studio features. Supports audio overview, video, infographic, report, presentation, and data table generation.

Note: v1.5.0 consolidated all content generation into this single endpoint.

Request:

# Generate a video (brief format)
curl -X POST http://localhost:3000/content/generate \
-H "Content-Type: application/json" \
-d '{
"content_type": "video",
"video_format": "brief",
"video_style": "documentary",
"language": "French",
"custom_instructions": "Focus on key takeaways"
}'

# Generate a presentation (detailed slideshow, short length)
curl -X POST http://localhost:3000/content/generate \
-H "Content-Type: application/json" \
-d '{
"content_type": "presentation",
"presentation_style": "detailed_slideshow",
"presentation_length": "short",
"language": "English"
}'

# Generate a data table (exports to Google Sheets)
curl -X POST http://localhost:3000/content/generate \
-H "Content-Type: application/json" \
-d '{
"content_type": "data_table",
"language": "English"
}'

Body Parameters:

ParameterTypeRequiredDescription
content_typestring✅ YesType: audio_overview, video, infographic, report, presentation, data_table
custom_instructionsstring❌ NoCustom focus/prompt (not available for report)
languagestring❌ NoOutput language (80+ supported)
video_stylestring❌ NoVisual style for video (see below)
video_formatstring❌ NoVideo format: brief (default), explainer
infographic_formatstring❌ NoInfographic format: horizontal (default), vertical
report_formatstring❌ NoReport format: summary (default), detailed
presentation_stylestring❌ NoStyle: detailed_slideshow (default), presenter_notes
presentation_lengthstring❌ NoLength: short, default
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse existing session

Content Types and Export Options:

Content TypeOptionsCustom PromptExport Type
audio_overviewlanguage only✅ YesWAV file
videobrief/explainer + 6 visual styles✅ YesMP4 file
infographichorizontal/vertical✅ YesPNG file
reportsummary/detailed❌ NoText (in response)
presentationstyle + length options✅ YesGoogle Slides
data_tablelanguage only✅ YesGoogle Sheets

Note: report does not support custom prompts - only format and language options are available.

Presentation Style Options:

StyleDescription
detailed_slideshowFull slides with visuals and content
presenter_notesSlides with speaker notes

Presentation Length Options:

LengthDescription
shortCondensed (5-8 slides)
defaultStandard length (10-15)

Video Visual Styles:

StyleDescription
classroomEducational whiteboard style
documentaryProfessional documentary style
animatedMotion graphics and animations
corporateBusiness presentation style
cinematicFilm-quality dramatic style
minimalistClean, simple visuals

Success Response (200):

{
"success": true,
"data": {
"success": true,
"type": "video",
"status": "ready",
"message": "Video generated successfully"
}
}

Note: Media generation can take several minutes. Use /content/download to retrieve files or export URLs.


16b. Generate a Study Aid​

POST /content/study-aid​

Generate flashcards or a quiz from every source in the notebook. This is a Studio artifact type the browser-driven /content/generate never exposed, so it is available over the internal API only.

The call blocks until generation finishes, polling every five seconds for up to fifteen minutes.

Request:

curl -X POST http://localhost:3000/content/study-aid \
-H "Content-Type: application/json" \
-d '{
"notebook_id": "74912e55-34a4-4027-bdcc-8e89badd0efd",
"kind": "flashcards",
"focus": "Concentrate on the terminology introduced in chapter 3"
}'

Body Parameters:

ParameterTypeRequiredDescription
kindstring✅ Yesflashcards or quiz
notebook_urlstring❌ NoNotebook URL
notebook_idstring❌ NoNotebook UUID, used instead of notebook_url
focusstring❌ NoFree-text steer for the generator (default: none)
languagestring❌ NoOutput language (default: the server's configured content language)

With neither notebook_url nor notebook_id, the active notebook is used. An unrecognised language is refused rather than silently replaced.

Success Response (200):

{
"success": true,
"data": {
"status": "completed",
"title": "Flashcards: Nonviolent Communication",
"artifactId": "3f0b9c21-7a4e-4d55-9f12-6c8e0a1b2d34"
}
}

Error Response (200 with success: false):

{
"success": false,
"data": { "status": "timeout", "artifactId": "3f0b9c21-7a4e-4d55-9f12-6c8e0a1b2d34" },
"error": "Generation timeout"
}

The payload is still present when generation does not complete, so you can retrieve the artifact later with GET /content. Other failures — kind must be 'flashcards' or 'quiz', No notebook specified, notebook has no sources — come back the same way, with no data.

Generation requires a notebook you own: NotebookLM refuses Studio creation on a notebook merely shared with you.

Response Time: 1–5 minutes.


16c. Generate a Mind Map​

POST /content/mind-map​

Generate a mind map from the notebook's sources and save it to the notebook. The response carries the map itself as a JSON string, so you can render it without a second call.

Request:

curl -X POST http://localhost:3000/content/mind-map \
-H "Content-Type: application/json" \
-d '{
"notebook_id": "74912e55-34a4-4027-bdcc-8e89badd0efd",
"title": "NVC overview",
"focus": "Organise around the four steps"
}'

Body Parameters:

ParameterTypeRequiredDescription
notebook_urlstring❌ NoNotebook URL
notebook_idstring❌ NoNotebook UUID, used instead of notebook_url
titlestring❌ NoTitle of the saved map (default: Mind Map)
focusstring❌ NoFree-text steer for the generator (default: none)
languagestring❌ NoOutput language (default: the server's configured content language)

With neither notebook_url nor notebook_id, the active notebook is used.

Success Response (200):

{
"success": true,
"data": {
"mindMapId": "5d8a1c33-0e67-4b92-8c41-72f5b0a9e118",
"title": "NVC overview",
"json": "{\"nodes\":[{\"id\":\"root\",\"label\":\"Nonviolent Communication\"}]}"
}
}

json is the raw mind-map document as returned by NotebookLM, kept as a string; its internal structure is not normalised by this server, so treat the example above as illustrative only. mindMapId is null when the map was generated but the save step returned no identifier.

Error Response (200 with success: false):

{
"success": false,
"error": "notebook has no sources"
}

As with the study aid, the notebook must be one you own.


16d. Research Web Sources​

POST /content/research​

Run NotebookLM's Fast Research against the open web and return the sources it finds, optionally importing them into the notebook in the same call.

The call starts the research task and then polls every five seconds for up to two minutes. If nothing has been found by then it returns an empty list rather than an error.

Request:

curl -X POST http://localhost:3000/content/research \
-H "Content-Type: application/json" \
-d '{
"notebook_id": "74912e55-34a4-4027-bdcc-8e89badd0efd",
"query": "empirical studies on nonviolent communication in schools",
"import": false
}'

Body Parameters:

ParameterTypeRequiredDescription
querystring✅ YesWhat to research
notebook_urlstring❌ NoNotebook URL
notebook_idstring❌ NoNotebook UUID, used instead of notebook_url
importboolean❌ NoAdd the discovered sources to the notebook (default: false)

With neither notebook_url nor notebook_id, the active notebook is used.

Success Response (200):

{
"success": true,
"data": {
"taskId": "task-9f3c1a7e",
"imported": 0,
"sources": [
{
"url": "https://example.org/nvc-in-schools",
"title": "Nonviolent Communication in Schools: a review",
"description": "A 2023 review of classroom interventions."
}
]
}
}

description is absent when the result carried none. imported is the number of sources actually added, and stays 0 unless import was true. taskId is null when the poll found no task.

Error Response (200 with success: false):

{
"success": false,
"error": "query is required"
}

Response Time: up to 2 minutes.


17b. Download/Export Content​

GET /content/download​

Download or export generated content. Supports file downloads (audio, video, infographic) and Google exports (presentation, data_table).

Request:

# Download video file
curl "http://localhost:3000/content/download?content_type=video&output_path=/path/to/video.mp4"

# Download infographic
curl "http://localhost:3000/content/download?content_type=infographic&output_path=/path/to/image.png"

# Export presentation to Google Slides (returns URL)
curl "http://localhost:3000/content/download?content_type=presentation"

# Export data table to Google Sheets (returns URL)
curl "http://localhost:3000/content/download?content_type=data_table"

Query Parameters:

ParameterTypeRequiredDescription
content_typestring✅ YesType: audio_overview, video, infographic, presentation, data_table
output_pathstring❌ NoLocal path to save file (for downloadable types)
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse existing session

Export Types:

Content TypeExport TypeOutput
audio_overviewFile downloadWAV file
videoFile downloadMP4 file
infographicFile downloadPNG file
presentationGoogle SlidesgoogleSlidesUrl in response
data_tableGoogle SheetsgoogleSheetsUrl in response

Note: report is text-only and returned in the /content/generate response (no export option).

Success Response - File Download (200):

{
"success": true,
"data": {
"success": true,
"filePath": "/path/to/video.mp4",
"mimeType": "video/mp4"
}
}

Success Response - Google Slides Export (200):

{
"success": true,
"data": {
"success": true,
"googleSlidesUrl": "https://docs.google.com/presentation/d/abc123",
"mimeType": "application/vnd.google-apps.presentation"
}
}

Success Response - Google Sheets Export (200):

{
"success": true,
"data": {
"success": true,
"googleSheetsUrl": "https://docs.google.com/spreadsheets/d/xyz789",
"mimeType": "application/vnd.google-apps.spreadsheet"
}
}

Error Response (400):

{
"success": false,
"error": "Content type 'report' is not exportable. Report content is text-based and returned in the generation response."
}

18. List Content​

GET /content​

List all sources and generated content in a notebook.

Request:

curl "http://localhost:3000/content?notebook_url=https://notebooklm.google.com/notebook/abc123"

Query Parameters:

ParameterTypeRequiredDescription
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse existing session

Success Response (200):

{
"success": true,
"sources": [
{
"id": "source-1",
"name": "Introduction Document",
"type": "document",
"status": "ready"
}
],
"generatedContent": [
{
"id": "audio-overview",
"type": "audio_overview",
"name": "Audio Overview",
"status": "ready",
"createdAt": "2025-12-24T10:30:00Z"
}
],
"sourceCount": 3,
"hasAudioOverview": true
}

18b. Delete Generated Content​

DELETE /content/:contentId​

Delete one generated Studio artifact — a report, an audio overview, a mind map, a study aid — by its ID. The IDs come from GET /content.

Path Parameters:

ParameterTypeRequiredDescription
contentIdstring✅ YesID of the artifact to delete

Query Parameters:

ParameterTypeRequiredDescription
notebook_urlstring❌ NoNotebook URL
notebook_idstring❌ NoNotebook UUID, used instead of notebook_url

The notebook is passed in the query string, not in a body. With neither parameter, the active notebook is used.

Request:

curl -X DELETE \
"http://localhost:3000/content/3f0b9c21-7a4e-4d55-9f12-6c8e0a1b2d34?notebook_id=74912e55-34a4-4027-bdcc-8e89badd0efd"

Success Response (200):

{
"success": true,
"data": {
"notebookId": "74912e55-34a4-4027-bdcc-8e89badd0efd",
"contentId": "3f0b9c21-7a4e-4d55-9f12-6c8e0a1b2d34",
"deleted": true
}
}

deleted is always true on a successful call: the deletion is not verified against a fresh listing afterwards, unlike DELETE /notebooks/bulk-delete.

Error Response (200 with success: false):

{
"success": false,
"error": "No notebook specified (notebook_url or notebook_id)"
}

19. Download/Export Content​

GET /content/download​

Download or export generated content from NotebookLM.

Request:

# Download audio
curl "http://localhost:3000/content/download?content_type=audio_overview&output_path=/path/to/audio.mp3"

# Download video
curl "http://localhost:3000/content/download?content_type=video&output_path=/path/to/video.mp4"

# Export presentation (returns Google Slides URL)
curl "http://localhost:3000/content/download?content_type=presentation"

# Export data table (returns Google Sheets URL)
curl "http://localhost:3000/content/download?content_type=data_table"

Query Parameters:

ParameterTypeRequiredDescription
content_typestring✅ YesType: audio_overview, video, infographic, presentation, data_table
output_pathstring❌ NoLocal path to save file (for audio, video, infographic)
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse existing session

Success Response - File Download (200):

{
"success": true,
"filePath": "/path/to/audio.mp3",
"mimeType": "audio/mpeg",
"size": 1234567
}

Success Response - Export (200):

{
"success": true,
"googleSlidesUrl": "https://docs.google.com/presentation/d/...",
"googleSheetsUrl": "https://docs.google.com/spreadsheets/d/..."
}

Note: Report content is text-based and returned directly in the /content/generate response.


20. Create Note​

POST /content/notes​

Create a note in the NotebookLM Studio panel. Notes are user-created annotations that appear in your notebook alongside sources, allowing you to save research findings, summaries, key insights, or any custom content.

Request:

curl -X POST http://localhost:3000/content/notes \
-H "Content-Type: application/json" \
-d '{
"title": "Key Findings Summary",
"content": "## Main Points\n\n1. First important finding\n2. Second key insight\n3. Conclusion and next steps"
}'

Body Parameters:

ParameterTypeRequiredDescription
titlestring✅ YesTitle of the note
contentstring✅ YesContent/body of the note (supports markdown)
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse existing session

Success Response (200):

{
"success": true,
"data": {
"success": true,
"noteTitle": "Key Findings Summary",
"status": "created"
}
}

Error Response (400):

{
"success": false,
"error": "Missing required field: title"
}

Use Cases:

  • Save research summaries from NotebookLM conversations
  • Create custom annotations for specific sections
  • Store key quotes and references
  • Build a structured outline from notebook content

20b. List Notes​

POST /content/notes/list​

List the notes saved in the notebook's Studio panel, with their titles and the short detail line NotebookLM shows beneath each one.

This route is browser-driven: it opens or reuses a session, scrolls the Studio panel to force the older notes to load, and reads them from the page. Expect seconds, not milliseconds, and expect it to be sensitive to NotebookLM interface changes.

Request:

curl -X POST http://localhost:3000/content/notes/list \
-H "Content-Type: application/json" \
-d '{
"notebook_url": "https://notebooklm.google.com/notebook/74912e55-34a4-4027-bdcc-8e89badd0efd"
}'

Body Parameters:

ParameterTypeRequiredDescription
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse an existing session

Without notebook_url the active notebook is used, then the configured default notebook. Note that this route takes a URL only — unlike the Studio routes above, it has no notebook_id parameter.

Success Response (200):

{
"success": true,
"data": {
"success": true,
"notes": [
{
"id": "note-4b21",
"title": "Key Findings Summary",
"details": "3 sources · 12 Jan"
},
{ "title": "Open questions" }
]
}
}

Both id and details are optional: a note is only guaranteed to carry a title. The data object repeats the success flag and carries an error string when the scrape fails.


20c. Read a Note​

POST /content/notes/get​

Return the title and full text of one note, identified by title or by ID.

Browser-driven like the listing above: the note is located in the Studio panel, opened, and its text read from the page.

Request:

curl -X POST http://localhost:3000/content/notes/get \
-H "Content-Type: application/json" \
-d '{
"note_title": "Key Findings Summary"
}'

Body Parameters:

ParameterTypeRequiredDescription
note_titlestring✅ One ofTitle of the note to read
note_idstring✅ One ofID of the note, from POST /content/notes/list
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse an existing session

At least one of note_title and note_id must be present; the other is optional.

Success Response (200):

{
"success": true,
"data": {
"success": true,
"title": "Key Findings Summary",
"content": "## Main Points\n\n1. First important finding\n..."
}
}

Error Response (400):

{
"success": false,
"error": "Missing required parameter: note_title or note_id"
}

A note that cannot be found returns 200 with success: false and Note not found: "Key Findings Summary".

21. Save Chat to Note​

POST /content/chat-to-note​

Save the current chat discussion to a note. This captures the last response from NotebookLM and saves it as a note in the Studio panel.

Request:

curl -X POST http://localhost:3000/content/chat-to-note \
-H "Content-Type: application/json" \
-d '{
"title": "Summary of Key Points"
}'

Body Parameters:

ParameterTypeRequiredDescription
titlestring✅ YesTitle for the saved note
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse existing session

Success Response (200):

{
"success": true,
"data": {
"success": true,
"noteTitle": "Summary of Key Points",
"status": "saved"
}
}

Use Cases:

  • Capture important NotebookLM responses for later reference
  • Build a collection of insights from multiple questions
  • Create study notes from Q&A sessions

22. Convert Note to Source​

POST /content/notes/:noteTitle/to-source​

Convert an existing note into a source. This makes the note content available as a citable source in the notebook.

Request:

curl -X POST "http://localhost:3000/content/notes/My%20Research%20Note/to-source" \
-H "Content-Type: application/json" \
-d '{}'

Path Parameters:

ParameterTypeRequiredDescription
noteTitlestring✅ YesURL-encoded title of the note

Body Parameters:

ParameterTypeRequiredDescription
notebook_urlstring❌ NoTarget notebook URL
session_idstring❌ NoReuse existing session

Success Response (200):

{
"success": true,
"data": {
"success": true,
"noteTitle": "My Research Note",
"status": "converted"
}
}

Error Response (404):

{
"success": false,
"error": "Note not found: My Research Note"
}

Use Cases:

  • Promote important notes to be citable sources
  • Include your own research as part of the notebook's knowledge base
  • Make aggregated insights available for citation in future responses

23. Scrape Notebooks from NotebookLM​

GET /notebooks/scrape​

Scrape all notebooks from the user's NotebookLM account.

Request:

curl "http://localhost:3000/notebooks/scrape?show_browser=true"

Query Parameters:

ParameterTypeDescription
show_browserbooleanShow browser window for debug

Success Response (200):

{
"success": true,
"data": {
"notebooks": [
{
"id": "00000000-0000-0000-0000-000000000103",
"name": "Internal Family Systems",
"url": "https://notebooklm.google.com/notebook/00000000-0000-0000-0000-000000000103"
}
],
"total": 16,
"message": "Found 16 notebooks in NotebookLM account"
}
}

24. Bulk Import Scraped Notebooks​

POST /notebooks/import-from-scrape​

Scrape notebooks from NotebookLM and bulk import them into the library.

Request:

curl -X POST http://localhost:3000/notebooks/import-from-scrape \
-H "Content-Type: application/json" \
-d '{"auto_discover": false}'

Body Parameters:

ParameterTypeRequiredDescription
notebook_idsstring[]NoFilter: only import these notebook IDs
auto_discoverbooleanNoUse AI to generate metadata (slower)
show_browserbooleanNoShow browser window for debug

Success Response (200):

{
"success": true,
"data": {
"imported": [
{
"id": "00000000-0000-0000-0000-000000000103",
"name": "Internal Family Systems",
"status": "imported"
}
],
"errors": [],
"total_scraped": 16,
"total_imported": 16,
"total_errors": 0
}
}

Use Cases:

  • Initial library setup: import all existing notebooks at once
  • Sync new notebooks: re-run to import newly created notebooks
  • Selective import: use notebook_ids to import specific notebooks only

25. List a Notebook's Sources​

GET /notebooks/:id/sources​

Returns every source in the notebook with its ID and title. This is where the source IDs used by GET /notebooks/:id/sources/:sourceId and DELETE /content/sources/:id come from.

RPC-backed: no browser is started, and a 150-source notebook answers in about a second.

Example:

curl http://localhost:3000/notebooks/74912e55-34a4-4027-bdcc-8e89badd0efd/sources

Response:

{
"success": true,
"data": {
"notebookId": "74912e55-34a4-4027-bdcc-8e89badd0efd",
"count": 153,
"sources": [
{
"id": "c3ae2b1b-b362-46ae-9dc8-7b658a05955e",
"title": "A Guide to Non-violent Communication - CultureAlly"
}
]
}
}

26. Read a Source's Full Text​

GET /notebooks/:id/sources/:sourceId​

Returns the exact text NotebookLM indexed for that source — the content it reasons over, which the web UI only ever shows you in fragments. Use it to quote a source verbatim, to check what was really extracted from a PDF or a web page, or to hand the raw material to another tool.

Query parameters:

ParameterValuesDefaultDescription
formattext | htmltexthtml keeps headings, lists and links, but inlines images as base64
paginatetrue | falsetruefalse returns the whole document in one response
max_charsnumber20000Page size. Ignored when paginate=false
cursornumber0Where to resume — pass the nextCursor from the previous page

Pagination. Sources are long: the first PDF measured here ran to 157,716 characters. So by default you get one page at a time, and the response tells you how to get the rest:

FieldMeaning
totalCharsSize of the whole document
pageCharsSize of this page
offsetWhere this page starts
hasMoreWhether anything follows
nextCursorPass back as cursor for the next page (absent when done)
continuePlain-language instruction for the next call (same)

Pages are cut at the nearest line break — the nearest tag close, in HTML — so a page never ends mid-word. Concatenating every page reproduces the document exactly; that round trip is verified against a live 157,716-character source.

paginate=false returns everything in one response, which is the right call for a short source and an expensive one for a book.

One more thing: html is bigger than text — images are embedded as base64 data URIs, so the same PDF came back at 158 KB as text and 166 KB as HTML.

Example:

curl "http://localhost:3000/notebooks/74912e55-.../sources/c3ae2b1b-...?format=text"

Response:

{
"success": true,
"data": {
"id": "8e058298-b561-4b3a-954f-953075e30e37",
"title": "All-in-Fully-Committing-to-a-Life-of-Nonviolence.pdf",
"notebookId": "74912e55-34a4-4027-bdcc-8e89badd0efd",
"format": "text",
"content": "All-in Fully Committing to a Life of Nonviolence\n...",
"totalChars": 157716,
"pageChars": 19645,
"offset": 0,
"hasMore": true,
"nextCursor": 19645,
"continue": "Call read_source again with cursor: 19645 for the next 20000 characters. Pass paginate: false to get the whole document in one call instead."
}
}

The MCP equivalents are source_list and source_read; source_read also accepts source_name instead of an ID, and refuses to guess when the name matches more than one source.


📊 Limits and Quotas​

LimitValueConfigurable
Concurrent sessions10✅ Yes (MAX_SESSIONS)
Session timeout15 min✅ Yes (SESSION_TIMEOUT)
Request timeout120 sec❌ No (hardcoded)
Max question sizeUnlimited❌ No
NotebookLM rate limit50/day❌ No (Google limit)

🧪 Postman Collection​

Import this collection:

{
"info": {
"name": "NotebookLM MCP API",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Health Check",
"request": {
"method": "GET",
"url": "http://localhost:3000/health"
}
},
{
"name": "Ask Question",
"request": {
"method": "POST",
"url": "http://localhost:3000/ask",
"header": [{ "key": "Content-Type", "value": "application/json" }],
"body": {
"mode": "raw",
"raw": "{\"question\":\"What advice for parents?\",\"notebook_id\":\"parents-numerique\"}"
}
}
}
]
}

Complete API Documentation! ✅