> For the complete documentation index, see [llms.txt](https://docs.autocontentapi.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.autocontentapi.com/private-notebooks.md).

# Private Notebooks

Private Notebooks gives you a dedicated notebook account for keeping reusable sources, asking grounded questions with citations, and generating finished assets from the same source workspace.

The subscription is **€99 per month**. One license provides one dedicated notebook account and is activated within one business day after payment. Private Notebook operations do not consume AutoContent API credits; the subscription limits below apply instead.

{% hint style="warning" %}
Private Notebooks is an independent AutoContent API service. It is not provided, sponsored, endorsed, or officially affiliated with Google or NotebookLM. Notebook content, prompts, and generated outputs are processed by third-party AI and platform providers to fulfill requests. Only send content you are authorized to process, and account for this processing in your privacy notices.
{% endhint %}

## Authentication and Idempotency

Use your AutoContent API token on every request:

```http
Authorization: Bearer YOUR_API_TOKEN
```

An active Private Notebooks license is required. A notebook belongs to the customer that created it; another customer cannot read, change, query, or delete that notebook ID.

Every operation that changes state or asks a question also requires an `Idempotency-Key` header:

```http
Idempotency-Key: pn-create-018f4f6e-23b1-7ef1-a867-acde48001122
```

Use an opaque printable ASCII value between 8 and 192 characters. Keep the same key when retrying the same operation. Reusing it with different input returns `409 Conflict`.

The header is required for:

* `POST /dedicated-account/notebooks`
* `DELETE /dedicated-account/notebooks/:notebookId`
* `POST /dedicated-account/notebooks/:notebookId/sources`
* `POST /dedicated-account/notebooks/:notebookId/questions`
* `POST /Content/Create` when the body contains `notebookId`

It is not required for the `GET` endpoints.

## Endpoints

| Method   | Endpoint                                             | Purpose                                                  |
| -------- | ---------------------------------------------------- | -------------------------------------------------------- |
| `POST`   | `/dedicated-account/notebooks`                       | Create a notebook, optionally with initial sources       |
| `GET`    | `/dedicated-account/notebooks`                       | List your notebooks                                      |
| `GET`    | `/dedicated-account/notebooks/:notebookId`           | Get one owned notebook                                   |
| `DELETE` | `/dedicated-account/notebooks/:notebookId`           | Delete one owned notebook and its sources                |
| `POST`   | `/dedicated-account/notebooks/:notebookId/sources`   | Add sources to an owned notebook                         |
| `POST`   | `/dedicated-account/notebooks/:notebookId/questions` | Ask a grounded question                                  |
| `GET`    | `/dedicated-account/usage`                           | Read capacity and current rolling 24-hour usage          |
| `POST`   | `/Content/Create`                                    | Generate an asset from an owned notebook's saved sources |
| `GET`    | `/Content/Status/:requestId`                         | Poll a generated asset until it completes                |

Individual source deletion is not supported. Delete the notebook when all of its sources should be removed.

## Supported Sources

Each source has a `type`, `content`, and, for uploaded files, an optional `fileName`.

| Type      | `content`                 | Notes                                           |
| --------- | ------------------------- | ----------------------------------------------- |
| `text`    | Plain text                | Up to 500,000 characters                        |
| `website` | An `http` or `https` URL  | The provider reads the page                     |
| `youtube` | A YouTube URL             | `youtube.com` and `youtu.be` URLs are accepted  |
| `pdf`     | Base64-encoded PDF bytes  | Up to 50 MB; a base64 data URL is also accepted |
| `file`    | Base64-encoded file bytes | Up to 50 MB; include `fileName`                 |

`file` accepts `.pdf`, `.txt`, `.md`, `.csv`, `.docx`, `.pptx`, `.xlsx`, `.mp3`, `.wav`, `.m4a`, `.png`, `.jpg`, `.jpeg`, and `.webp` files.

## Create a Notebook with cURL

Creating a notebook may include an empty `sources` array or up to 20 initial sources. Add more in batches of 20 until the notebook reaches its 100-source capacity:

```bash
curl -X POST "https://api.autocontentapi.com/dedicated-account/notebooks" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Idempotency-Key: pn-create-018f4f6e-23b1-7ef1-a867-acde48001122" \
  -H "Content-Type: application/json" \
  -d '{
    "sources": [
      {
        "type": "text",
        "content": "Our annual plan includes priority support and unlimited team seats."
      },
      {
        "type": "website",
        "content": "https://example.com/product"
      }
    ]
  }'
```

A new request returns `201 Created`:

```json
{
  "notebookId": "provider-notebook-id",
  "sourceCount": 2,
  "sources": [
    {
      "index": 0,
      "success": true,
      "sourceId": "source-record-id-1"
    },
    {
      "index": 1,
      "success": true,
      "sourceId": "source-record-id-2"
    }
  ],
  "replay": false
}
```

An idempotent replay returns `200 OK` with `replay: true`. Source ingestion can partially succeed, so inspect every item in `sources` even when the HTTP request succeeds. A failed item has `success: false` and an `errorMessage`.

## Add a PDF Source

Base64-encode the file bytes and send them as `content`:

```bash
curl -X POST "https://api.autocontentapi.com/dedicated-account/notebooks/NOTEBOOK_ID/sources" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Idempotency-Key: pn-source-018f4f76-6ac8-7b17-bbf8-acde48001122" \
  -H "Content-Type: application/json" \
  -d '{
    "sources": [
      {
        "type": "pdf",
        "fileName": "annual-report.pdf",
        "content": "JVBERi0xLjcK..."
      }
    ]
  }'
```

The response identifies the result for each submitted source:

```json
{
  "notebookId": "NOTEBOOK_ID",
  "sources": [
    {
      "index": 0,
      "success": true,
      "sourceId": "source-record-id-3"
    }
  ],
  "replay": false
}
```

## Ask a Question and Read Citations

Questions can contain up to 5,000 characters:

```bash
curl -X POST "https://api.autocontentapi.com/dedicated-account/notebooks/NOTEBOOK_ID/questions" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Idempotency-Key: pn-question-018f4f8b-8591-7c5f-98ea-acde48001122" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "What are the main findings and which sources support them?"
  }'
```

`citations` is an object keyed by the citation marker used in the answer:

```json
{
  "notebookId": "NOTEBOOK_ID",
  "answer": "The report identifies three main findings.[1]",
  "citations": {
    "1": {
      "citationDocument": "annual-report.pdf",
      "citationTitle": "1",
      "citationText": "Relevant source excerpt"
    }
  },
  "replay": false,
  "usage": {
    "used": 17,
    "limit": 200,
    "resetsOn": "2026-08-16T09:42:31.000Z"
  }
}
```

Citation fields depend on the underlying source and may be empty. Treat the `citations` keys as strings and render only citations returned by the API.

## Licensed Generation Capacity

Every notebook-bound generation runs on the same dedicated account assigned to your license. It uses the notebook's existing sources, does not consume AutoContent generation credits, and never rotates through the shared account pool.

The supported `outputType` values are:

* `audio`
* `video`
* `text`
* `faq`
* `study_guide`
* `timeline`
* `briefing_doc`
* `quiz`
* `infographic`
* `slide_deck`
* `datatable`

Submit the job through `/Content/Create` with the owned `notebookId`, then poll `/Content/Status/:requestId` exactly as you would for other AutoContent jobs. Do not add `resources`, `topic`, `projects`, feeds, research IDs, channels, or episode IDs to a notebook-bound request. Add sources to the notebook first so the persistent source workspace remains the only generation context.

```bash
curl -X POST https://api.autocontentapi.com/Content/Create \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pn-asset-018f4f6e-23b1-7ef1-a867-acde48001122" \
  -d '{
    "notebookId": "NOTEBOOK_ID",
    "outputType": "infographic",
    "language": "English"
  }'
```

The create response contains `request_id`. Poll its status until `status` is `100`. Depending on the output, the terminal response contains grounded `response_text` and citations, or a downloadable field such as `audio_url`, `video_url`, `image_url`, `briefing_doc_url`, `slide_deck_url`, or `datatable_url`. Replaying the same request with the same idempotency key returns the same request ID and does not submit a second provider generation.

## Node.js Example

This example creates a notebook and asks it a question using the built-in `fetch` available in Node.js 18 and later:

```javascript
import { randomUUID } from 'node:crypto';

const baseUrl = 'https://api.autocontentapi.com';
const token = process.env.AUTOCONTENT_API_TOKEN;

async function api(path, options = {}) {
  const response = await fetch(`${baseUrl}${path}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
      ...options.headers
    }
  });
  const body = await response.json();
  if (!response.ok) throw new Error(`${response.status}: ${JSON.stringify(body)}`);
  return body;
}

const created = await api('/dedicated-account/notebooks', {
  method: 'POST',
  headers: { 'Idempotency-Key': `create-${randomUUID()}` },
  body: JSON.stringify({
    sources: [{ type: 'text', content: 'Revenue grew 24% year over year.' }]
  })
});

const result = await api(
  `/dedicated-account/notebooks/${encodeURIComponent(created.notebookId)}/questions`,
  {
    method: 'POST',
    headers: { 'Idempotency-Key': `question-${randomUUID()}` },
    body: JSON.stringify({ question: 'How much did revenue grow?' })
  }
);

console.log(result.answer);
console.log(result.citations);
```

## Python Example

This example creates an empty notebook, uploads a PDF, and asks a question. Install the `requests` package first.

```python
import base64
import os
import uuid
from pathlib import Path

import requests

BASE_URL = "https://api.autocontentapi.com"
TOKEN = os.environ["AUTOCONTENT_API_TOKEN"]


def post(path, payload, operation):
    response = requests.post(
        f"{BASE_URL}{path}",
        headers={
            "Authorization": f"Bearer {TOKEN}",
            "Idempotency-Key": f"{operation}-{uuid.uuid4()}",
        },
        json=payload,
        timeout=120,
    )
    response.raise_for_status()
    return response.json()


notebook = post(
    "/dedicated-account/notebooks",
    {"sources": []},
    "create",
)
notebook_id = notebook["notebookId"]

pdf_bytes = Path("annual-report.pdf").read_bytes()
post(
    f"/dedicated-account/notebooks/{notebook_id}/sources",
    {
        "sources": [
            {
                "type": "pdf",
                "fileName": "annual-report.pdf",
                "content": base64.b64encode(pdf_bytes).decode("ascii"),
            }
        ]
    },
    "source",
)

answer = post(
    f"/dedicated-account/notebooks/{notebook_id}/questions",
    {"question": "Summarize the report's main risks."},
    "question",
)
print(answer["answer"])
print(answer["citations"])
```

In production, retain each idempotency key with its operation so a network retry sends the same key instead of generating a new one.

## List, Read, Delete, and Check Usage

These examples use the same Bearer token. Only deletion needs an idempotency key.

```bash
# List notebooks
curl "https://api.autocontentapi.com/dedicated-account/notebooks" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# Get one notebook
curl "https://api.autocontentapi.com/dedicated-account/notebooks/NOTEBOOK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# Check usage and limits
curl "https://api.autocontentapi.com/dedicated-account/usage" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# Delete a notebook and all of its sources
curl -X DELETE "https://api.autocontentapi.com/dedicated-account/notebooks/NOTEBOOK_ID" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Idempotency-Key: pn-delete-018f4fc2-0621-72f7-b095-acde48001122"
```

The list response wraps records in `notebooks`; the single-notebook response returns one record directly:

```json
{
  "notebooks": [
    {
      "notebookId": "NOTEBOOK_ID",
      "sourceCount": 3,
      "createdOn": "2026-08-15T08:30:00.000Z",
      "updatedOn": "2026-08-15T09:15:00.000Z"
    }
  ]
}
```

A successful deletion returns `success: true`, the deleted `notebookId`, and a `replay` flag.

Usage response:

```json
{
  "window": "rolling_24_hours",
  "windowStart": "2026-08-14T10:00:00.000Z",
  "observedOn": "2026-08-15T10:00:00.000Z",
  "usage": {
    "questions": { "used": 17, "limit": 200, "resetsOn": "2026-08-16T09:42:31.000Z" },
    "audio": { "used": 0, "limit": 6, "resetsOn": null },
    "video": { "used": 0, "limit": 6, "resetsOn": null },
    "reports": { "used": 0, "limit": 20, "resetsOn": null },
    "quizzes": { "used": 0, "limit": 20, "resetsOn": null }
  },
  "capacity": {
    "notebooks": 200,
    "sourcesPerNotebook": 100
  }
}
```

## Plan Limits

| Capability                                             |                                                 Limit |
| ------------------------------------------------------ | ----------------------------------------------------: |
| Dedicated accounts per license                         |                                                     1 |
| Notebooks                                              |                                                   200 |
| Sources per notebook                                   |                                                   100 |
| Grounded questions                                     |                          200 after each 24-hour reset |
| Audio overview account capacity                        |                            6 after each 24-hour reset |
| Video overview account capacity                        |                            6 after each 24-hour reset |
| Reports: FAQ, study guide, timeline, briefing document |                           20 after each 24-hour reset |
| Quizzes                                                |                           20 after each 24-hour reset |
| Infographics, slide decks, and data tables             | Provider-governed capacity; no invented numeric limit |

`text` generation uses the same question allowance as the direct questions endpoint. All listed output request and retrieval paths have been verified end to end. Upstream capacity can still change, and the API returns a clear provider error if the assigned account reaches a provider limit that has no published numeric allowance.

Google's published help says daily quotas reset after 24 hours but does not expose an account reset timestamp to this API. AutoContent therefore applies a conservative rolling 24-hour admission window and also surfaces upstream quota errors. Use `GET /dedicated-account/usage` instead of calculating availability locally; each used capability includes its next local `resetsOn` timestamp.

## Error Handling

| Status | Meaning                                                                                                      | Recommended action                                                                                                    |
| -----: | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
|  `400` | Invalid body, source, notebook ID, question, or idempotency key                                              | Correct the request before retrying                                                                                   |
|  `401` | Missing or invalid Bearer token                                                                              | Supply a valid AutoContent API token                                                                                  |
|  `403` | No active Private Notebooks license                                                                          | Wait for activation or restore the subscription                                                                       |
|  `404` | Notebook not found or not owned by the authenticated customer                                                | Verify the notebook ID and token                                                                                      |
|  `409` | The key was reused with different input, work is already in flight, or the prior mutation must be reconciled | If `Retry-After` is present, wait and retry the identical request with the same key; otherwise inspect the error code |
|  `429` | Notebook/source capacity or a rolling 24-hour allowance was reached                                          | Read `/dedicated-account/usage` and wait until `resetsOn` when applicable                                             |
|  `503` | The service, dedicated account, or third-party provider is temporarily unavailable                           | Retry the identical request with the same key and exponential backoff                                                 |

Private Notebook endpoints commonly return `error`, `errorMessage`, and optional `details`. Managed mutation conflicts may instead include `success: false`, `code`, and `error`. Parse the HTTP status first and preserve these fields in logs.
