Granola connector setup

Operator·4 minutes to read

Granola does not fit the "bring your own OAuth app" shape most other pages here describe. There is no client id, no client secret and no docs/connectors/README.md botseon oauth-app set step for it. Instead, a member creates an API key in the Granola desktop app and pastes it into the plugin sheet's own Connect field — the same pasted-key path sentry.md and stripe.md describe.

1. Create the API key in Granola

  1. The workspace needs a Business or Enterprise plan — on the free Basic plan there is no API key page at all.
  2. In the Granola desktop app, go to Settings -> Connectors -> API keys -> Create new key.
  3. Tick one or both access scopes (step 2 below explains what each one means), then Generate API Key and copy the grn_… value once. Paste it straight into the plugin sheet's Connect field.
  4. On an Enterprise workspace, if Create new key is missing or a scope is greyed out, a workspace admin has to enable it under Settings -> Workspace -> General -> API access for members -> Manage.

A key only ever sees what its owner can see: a personal key needs the owner's own access to a note, and a team note has to live in a workspace-visible folder before any key can read it.

2. The declared scope checklist

The plugin sheet shows Granola's two access scopes, in the API's own spelling (personal, public, API_KEY_CONNECTORS.granola in packages/core/src/connector-catalog.ts):

  • personal — notes you own, and notes shared with you in private folders.
  • public — notes visible to everyone in the workspace, including the Team space.

These gate which notes a read returns, not whether the read itself is allowed, so there is no single scope Connect requires. Botseon's catalogue declares both as the read set, so tick both when you create the key: a key declared with one scope connects, but its tools stay locked.

3. What the tool does

ToolReads
granola.list_foldersGET /v1/folders: the folders this key can access, with their parent-folder ids; paged by the cursor token, 1–30 per page.
granola.list_notesGET /v1/notes: notes with a finished AI summary, filtered by folder_id, created_after, created_before, updated_after; paged by the cursor token, 1–30 per page.
granola.get_noteGET /v1/notes/{note_id}: title, owner, link to the note, AI summary (markdown when the note has it, else plain text), attendees, calendar event with its organiser and invitees, and folders.
granola.get_transcriptGET /v1/notes/{note_id}/transcript: one page of transcript lines, up to 100 (follow cursor for the next), each attributed me (the note's owner) or them where Granola knows and otherwise left unattributed (the audio channel speaker.source is never read as the speaker), with the speaker's name or anonymous label when it has one.

This connector is read-only. Granola's API has no write endpoint for meeting data.

The field names the driver reads are the ones Granola's API reference documents, listed in packages/connectors/src/granola.contract.ts. The nightly connector-live run checks the real API's answers against that file and, when one is missing, names the endpoint and the field path, never a value. Every pull request runs that same live case against a simulated workspace through the real driver (packages/connectors/src/granola-live-smoke.test.ts).

4. Pitfalls

  • Scope, not a broken key: "why does the API return nothing?" is almost always a scope/visibility problem, not an invalid key — recheck the scopes ticked above against where the notes actually live.
  • No sandbox. Test against a dedicated folder rather than production notes.
  • Notes lag the meeting. A note is listed only after its AI summary exists, and a note still processing answers 404, which the connector reports as "could not find that resource".
  • Transcript auto-deletion, if a member or the workspace enabled it, removes transcripts from the API too: granola.get_transcript then returns an empty page.
  • All data is stored in the US — Granola offers no EU or UK data residency.

Last verified against build 445930e.