Notion AI is genuinely useful, but it only speaks Notion's own chat API. If you want Cursor, Postman, or any OpenAI Chat Completions client to talk to it, you need a translation layer.
That layer exists. NotionChat, originally built by mughu-id, is a FastAPI proxy that routes OpenAI-format requests to Notion AI's runInferenceTranscript endpoint using your browser session cookie, and streams the NDJSON response back as OpenAI chunks. It reached 90 stars on GitHub.
Then it went quiet. The last upstream push was in July 2026.
I rely on tools like this, and an unmaintained proxy that holds my Notion session cookie is not something I want to just leave lying around. So instead of forking-and-forgetting or rewriting from scratch, I adopted it: a maintained continuation with the full history and MIT license preserved.
Why adopt instead of rewrite
The hard part of this codebase — parsing Notion's transcript protocol and reassembling streamed responses — already worked and had real users. What was missing was everything around it: there were no tests, no CI, no security policy, and no Responses API endpoint.
Rewriting would have thrown away the working core to rebuild the easy parts. Adopting meant the opposite order of work, and honestly, a better discipline.
Rule one: tests before changes
You can't responsibly change code you didn't write until you can prove what it currently does. So the first thing the continuation got was a characterization test suite — ten test files covering:
- chat completions (streaming and non-streaming)
- NDJSON parsing
- model listing and aliases
- concurrency and thread state
- the tools bridge
- security behavior (auth checks, bind protection)
Only with that safety net in place did I start changing behavior.
What the continuation adds
A test suite and CI. Ten test files where there were zero, a GitHub Actions workflow running them on every push, dependabot, a SECURITY.md, and a changelog.
Security hardening. This proxy holds a live Notion session cookie, so the details matter:
- API keys are verified with
secrets.compare_digest(timing-safe comparison) - the server refuses to bind to
0.0.0.0with a default or empty API key - state files are written atomically with POSIX
0600permissions - upstream error responses are sanitized before they reach clients
The OpenAI Responses API. Next to POST /v1/chat/completions, the continuation adds POST /v1/responses, mapped to and from Chat Completions. GET /v1/models is built dynamically from Notion's available models, with friendly aliases (opus-4.8, gpt-4o, sonnet-4.6) mapped to Notion's internal IDs — and a stale-cache fallback if Notion can't be reached. Streaming is standard append-only SSE, the way OpenAI clients expect it.
Quickstart
git clone https://github.com/HoosseinRahimi/Notion-AI-to-OpenAI-Compatible.git
cd Notion-AI-to-OpenAI-Compatible
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
pip install -e .
cp .env.example .env # set NOTIONCHAT_API_KEY
Grab your Notion cookie from the browser (DevTools → Application → Cookies — you need token_v2), then:
notion init --cookie "notion_browser_id=...; token_v2=..."
notion serve
The server runs at http://127.0.0.1:1994:
curl http://127.0.0.1:1994/v1/models \
-H "Authorization: Bearer <redacted>"
curl http://127.0.0.1:1994/v1/chat/completions \
-H "Authorization: Bearer <redacted>" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'
Point Cursor or any other OpenAI client at http://127.0.0.1:1994/v1 and it just works.
Honest limitations
This is an unofficial project, not affiliated with Notion. It authenticates with your browser cookie, so Notion's Terms of Service and your workspace plan limits apply. One operational gotcha worth knowing: Notion ties AI permission to the IP address where you logged in, so a cookie copied from your home PC to a VPS often fails with 403 trust-rule-denied. Run it on the machine (or exit IP) where you logged in, or route it through NOTION_PROXY. Tool calling is experimental and feature-gated, because Notion AI has no native function calling — the bridge compiles model text into tool_calls with guardrails.
What adoption taught me
Maintaining someone else's code is a different discipline from writing your own. You earn the right to change things by first proving — with tests — that you understood them. The boring work (tests, CI, hardening) is the contribution; features are what it unlocks.
If the proxy saves you time, a star on the maintained repo helps the next person find the version that's still alive. Issues and PRs are welcome — and if the original project resumes, I'll happily upstream everything.
Top comments (0)