When to use it
A Supabase project where you want a public API surface that is not tied to Supabase's own keys, and that you can version and meter.
What to grant
The service-role key bypasses row-level security, so treat it as a full-access credential. Where possible, point the resource at a table whose contents are already safe to expose, or use a dedicated Postgres role through the External Postgres source instead.
Setup
1. Find your project URL and service-role key
In the Supabase dashboard, open Project Settings, then API. The URL looks like https://abcdefgh.supabase.co. Copy the service_role key, not the anon key: the anon key is subject to row-level security and will usually return nothing.
2. Confirm the table has an id column
Single-record reads and ordering both use id.
3. Connect it in EndpointOS
Create a resource, choose Supabase, and paste the URL, the service-role key and the table name. The key is encrypted at rest and never shown again.
4. Consider whether the service-role key is too much
Because it bypasses row-level security, this credential can read and write every table in the project. If that is more than you want to hand over, use External Postgres with a role scoped to one table.
What you will be asked for
- Project URL: Your Supabase project URL, from Project Settings then API. It looks like https://abcdefgh.supabase.co.
- Service role key, stored encrypted: From Project Settings then API. The service role key bypasses row-level security, so it stays server-side and is stored encrypted. Never use the anon key here.
- Table: The table to expose. It must have an id column, which is what record reads and ordering use.
What the API supports for this source
Generated from the same declaration the API enforces on every request, so it cannot promise something a request would be rejected for.
| Filtering | equals, not equal, one of, greater than, greater or equal, less than, less or equal on any declared field |
|---|---|
| Sorting | By id only |
| Search (q) | Not supported |
| Writes | create, update, delete |
| Paging | limit and offset |
| Record count | Exact: the total describes the filtered set |
Worth knowing first
- Filtering supports the full documented grammar: equality, not-equal, one-of, and the four comparisons. They are translated to PostgREST's own operators.
- Pages are explicitly ordered by id, so paging cannot skip or repeat rows.
- Record counts are exact: the total in a list response describes the filtered set, not just the page.
If something goes wrong
Empty results from a table you know has rows
Why: An anon key was used instead of the service-role key, so row-level security filtered everything out.
Fix: Use the service_role key from Project Settings then API.
column does not exist
Why: The table name or a declared field does not match the table.
Fix: Check the table name and the field names, which are case-sensitive.
Project URL must be a full https:// URL
Why: A host without a scheme, or an http:// URL, was pasted.
Fix: Use the full https://your-project.supabase.co URL.