Skip to main content
Every Powabase project keeps its connection details in one place: the Connect modal in the Studio. It holds the Project URL, both API keys (Anon and Service Role), the JWT Secret, the Database URL, and ready-to-paste Postgres connection strings in nine driver formats. Open it once, copy what you need, and you can call any part of the platform.
Breaking change in 0.12.0: most /api/* routes now require the service role key. A signed-in user’s access token works only on the 16 conversation routes listed in Which key for which route. Knowledge bases, sources, agent configuration, workflows and every other /api/* route answer it with 403. If your app sends user tokens to the AI API, read Migrating from earlier versions before you upgrade.

Open the Connect modal

In the Studio at app.powabase.ai, click the Connect button in the top-right of your project header.
Powabase Studio header with the Connect button highlighted in the top-right corner

The Connect button lives in the project header.

The dialog has two tabs. API Keys lists everything you need to authenticate HTTP and Postgres clients. Connection Strings ships pre-filled snippets for psql, the generic URI, Node.js (pg), Python (psycopg2), Go (database/sql), JDBC, .NET, PHP, and SQLAlchemy: nine in all. Copy buttons sit next to every value. Secret fields hide by default; click the eye icon to reveal.
Connect to your project modal, API Keys tab. Shows Project URL, Anon (Publishable) Key, and three masked fields: Service Role (Secret) Key, JWT Secret, and Database URL.

The API Keys tab: every credential your project exposes lives here.

You can also open the modal by appending ?showConnect=true to any project URL, which is handy for deep-linking from internal docs.

What’s in the modal, and where to use each value

The rest of this guide uses the Service Role (Secret) Key as API_KEY. It authenticates every endpoint under /api/*, which is what most of the platform docs assume. Most of those endpoints accept nothing else; see Which key for which route.
Never expose the Service Role key, JWT Secret, or Database URL to a browser, mobile app, or any environment outside your control. The Anon key is the only field in the modal safe to bundle into a client.

Which key for which route

Every /api/* route takes a bearer token in Authorization. There are two kinds of caller:
  • Your backend, with the service role key. Send the key as both apikey and Authorization: Bearer. Every /api/* route accepts it. The Studio calls the API the same way.
  • A signed-in end user, with their own access token. Send the Anon key as apikey and the user’s access token (the JWT your project’s Auth service returned at sign-in) as Authorization: Bearer. Only the 16 conversation routes below accept it, and only for that user’s own sessions and runs.
Every other /api/* route answers an end-user token with 403:
That covers knowledge bases and knowledge-base search, sources, agent and orchestration configuration (tools, knowledge-base assignments, MCP servers, hooks), workflows, Copilot, tools, context handlers, AI provider keys, settings, observability, and the /api/database/* proxy. Two routes take no bearer at all because they verify their own secret: the inbound workflow webhook (POST /api/webhooks/{webhook_id}, verified by the per-webhook secret; see Webhooks) and the documentation search used by the Studio’s Copilot (POST /api/internal/docs/search).
Never ship the service role key to a browser or a mobile app. Anyone who holds it can call every route as an administrator. Browsers and apps call the conversation routes with the signed-in user’s own token, and everything else goes through your backend.

End-user routes

These are the only routes an end user’s access token may call. The service role key works on them too. A session, run or paused run that belongs to someone else, or that your backend created without a user_id, answers 404 as if it didn’t exist. There is no end-user route to create or delete an orchestration session: a run creates one.

Rules for end-user runs

  • The token must name the user and expire. The API accepts a JWT with audience authenticated, signed with your project’s JWT secret, whose sub is a UUID and which carries an exp. Anything else answers 401. Tokens from your project’s Auth service always qualify; this matters only if you mint your own.
  • The run uses the agent’s own knowledge bases. An end user’s run body may not set knowledge_bases, runtime_knowledge_bases, context_handler_id, or by-reference context_items (items with an item_id). Sending any of them answers 403 with a body that names the fields:
    context_override and by-value context_items (items with text) are still allowed, because the user supplies that text themselves.
  • An end user can continue only their own existing session, and can never name a new one. A session_id in a run body or a path must be a string of at most 255 characters, or the request answers 400. A run continues a session only if it already exists and belongs to the caller, for the same agent or orchestration; any other session_id answers 404 (a streamed run ends with the event {"event": "error", "error": "Session not found"}). To start a conversation, omit session_id (the run creates a session owned by the user and returns its id) or call POST /api/agents/{agent_id}/sessions. This stops a user from creating a session under an id your backend would later pick, such as one derived from a phone number, and reading or steering what your backend’s runs say in it.
  • An end user approves only the paused runs they started. A run your backend started with the service role key has no end-user owner, even in a session created with that user’s user_id, so only the service role key can approve it. Relay the user’s decision from your backend.

Running agents for a user from your backend

When a run needs something end users can’t send, such as knowledge bases chosen per request, run it from your backend with the service role key. Pass user_id when you create the session (POST /api/agents/{agent_id}/sessions with {"user_id": "<the user's id>"}) so the conversation still belongs to that user: they can list it, read it, and continue it with their own token. Only the service role key may set user_id; an end user who sends it gets 403. A run made with the service role key is a service-role run, even in a session owned by a user. Its data tools don’t act as that user; see the next section.

What agent data tools act as

An agent’s database_query, database_write, storage_read and storage_write tools act as whoever started the run:
When your backend runs an agent for a user with the service role key, the agent’s data tools see everything in the tables and buckets they’re configured with, whoever the session belongs to. Configure such an agent only with tables and buckets every user it serves may see in full, or let the user’s own token start runs of agents that carry data tools.
The per-tool limits (which tables can be configured, what database_query accepts, the 30-second timeout, and the bucket and path rules for storage tools) are in the Tools reference.

Migrating from earlier versions

Before 0.12.0, most /api/* routes accepted any signed-in user’s token. To upgrade:
  • If your backend forwarded an end-user JWT to knowledge-base or source routes (or any other route outside the table above), switch those calls to the service role key.
  • If your client sent knowledge_bases on a run (or runtime_knowledge_bases, context_handler_id, or by-reference context_items), configure the knowledge bases on the agent instead with POST /api/agents/{id}/knowledge-bases. If the choice has to be made per request, run the agent from your backend with the service role key and pass user_id when you create the session.
  • If your clients started sessions under ids they chose, have them omit session_id on the first run or call POST /api/agents/{agent_id}/sessions, and use the id that comes back.
  • If you mint your own user JWTs, give them a UUID sub and an exp.
  • If you self-host, set SERVICE_ROLE_KEY on the API service. Without it no caller counts as the service role: a request that bears the service role key is decoded as an end-user token and answers 401, and every management route is unreachable.
  • If an agent has database tools, check its configured tables. They must be plain or partitioned tables or views created WITH (security_invoker = true), and service-role runs now reach exactly those tables and nothing else.

Use it from code

1

Set your Base URL and headers

Every request to /api/* and /rest/v1/* needs both an apikey header and an Authorization: Bearer header. From your backend, set both to the Service Role (Secret) Key; that’s what /api/* and server-side PostgREST calls use. (A browser calling an end-user conversation route sends the Anon key as apikey and the user’s access token as Authorization instead.)Endpoint: Headers: apikey + Authorization
Sending only one of the two headers is the most common cause of 401 errors. PostgREST and Kong both reject the request.
2

Verify your setup

Hit a cheap, idempotent endpoint to confirm the credentials work end-to-end. An empty array and a populated array both count as success.Endpoint: GET /api/agents
Response:
3

Connect directly to Postgres (optional)

For migrations, dashboards, ORMs, or any tool that speaks the Postgres wire protocol, grab the Database URL from the API Keys tab, or open the Connection Strings tab and copy a pre-built snippet in your language. Use this from servers and trusted environments only.Endpoint: Postgres wire protocol
The Database URL embeds the database password in cleartext. Treat it like the Service Role key: never commit it, never expose it client-side, and rotate the database password (Studio → Settings → Database) if it leaks.

What’s Next

Quickstart

Build an end-to-end RAG agent in 5 minutes.

Database Access

AI schema vs public schema, plus PostgREST and direct Postgres usage.

Architecture

How Kong routes /api/, /rest/v1/, /auth/, and /storage/ to your project’s stack.