What you’ll build
An authenticated chat where every Supabase user has their own Polpo session memory, analytics, and (later) billing pass-through. Your Next.js app verifies the Supabase session on the server, then forwards the user’s ID to Polpo on every chat call. You get:- Per-user chat memory (sessions auto-scoped to
user.id) - Per-user analytics (filter dashboard by
user) - Audit trail (every session, task, run carries the user id)
- Foundation for per-user billing via the upcoming Autumn bridge
Prerequisites
Supabase project with auth enabled
Email/password, OAuth, magic links — any Supabase auth method works. You only need the server-side helper to read the current user.
Polpo project + API key
Follow the quickstart to create a project and grab a service-role API key (
sk_live_...). Server-side only — never ship it to the browser.How it fits together
user field.
Step 1 — Install
Step 2 — Verify the session and call Polpo
Server-side route handler. Reads the Supabase session via cookies, rejects unauthenticated requests, and streams the chat completion back to the browser withuser: user.id attached.
app/api/chat/route.ts
Step 3 — Stream the response in your client
Plainfetch + the standard SSE parsing pattern. Replace this with @polpo-ai/react’s useChat hook once you wire PolpoProvider against /api/chat.
app/chat/page.tsx
Step 4 (optional) — List a user’s past sessions
Polpo auto-creates a session per chat and tags it with theuser field. You can list a single user’s sessions from your server.
The typed
polpo.getSessions() helper doesn’t currently take a user filter parameter. Until it does, hit the underlying endpoint directly — GET /v1/chat/sessions?user=<id> does support the filter server-side. We’ll add a typed param to the SDK in a later release.app/api/sessions/route.ts
What this gives you
- Per-user memory. Every session is keyed on
user.id. The agent’s recall stays scoped to the right person. - Per-user analytics. Filter completions, tasks, and runs by
userin the dashboard. - Audit trail. Every session, task, and run row stores the user id — useful for support, abuse review, and compliance.
- Billing foundation. When the Autumn bridge ships, the same
userfield becomes the customer key for per-user metering and pass-through pricing.
What we deliberately don’t do
- Polpo never verifies the Supabase JWT. Your API key is the trust anchor. Verify the session in your server, then forward
user.id— Polpo trusts the caller because the caller has the API key. - We don’t compete with Supabase Auth. Bring your auth — we run the agents.
Troubleshooting
401 Unauthorized from Polpo
Check POLPO_API_KEY is set in the server environment and not prefixed with NEXT_PUBLIC_. The SDK sends it as Authorization: Bearer <key>.
user field shows up as null in the dashboard
The user field must be passed in the request body, not as a header. With the SDK, that’s polpo.chatCompletionsStream({ ..., user: user.id }). With raw fetch, include "user": "<id>" as a top-level body field.
Sessions aren’t being scoped per user
Confirm@polpo-ai/sdk >= 0.6.23 — earlier versions silently dropped the user field. Run pnpm why @polpo-ai/sdk to verify.
Next steps
- Publishable keys (coming soon). A
pk_*token will let you call Polpo directly from the browser, removing the route-handler hop for low-risk endpoints. - Autumn bridge (coming soon). Plug
user.idinto Autumn for per-user metering and Stripe billing pass-through. - Narrative version. For the “why” behind this pattern, read Per-user agents with Supabase Auth on the blog.