When to use it
A transactional table you own and want to expose for reads and writes. It is the best-supported external source: the full filter grammar works, and record counts are exact.
What to grant
A dedicated role with only the privileges the resource needs on the single table. Grant SELECT alone for a read-only resource; add INSERT, UPDATE and DELETE only if the resource is read-write. Never the owner or a superuser.
Setup
1. Create a role for EndpointOS
A separate role means you can revoke this integration without touching anything else.
CREATE ROLE endpointos LOGIN PASSWORD 'a-long-random-password';2. Grant it access to one table
Grant on the specific table rather than the schema, so a new table is not exposed by accident.
GRANT USAGE ON SCHEMA public TO endpointos;
GRANT SELECT ON public.your_table TO endpointos;
-- read-write resources only:
-- GRANT INSERT, UPDATE, DELETE ON public.your_table TO endpointos;3. Confirm the table has an id column
Single-record reads and result ordering both use id. A table without one cannot be exposed yet.
\d public.your_table4. Require TLS
Add sslmode=require to the connection string unless your host does not support it. The connection string is encrypted at rest, but the connection itself should be encrypted in transit.
5. Connect it in EndpointOS
Create a resource, choose External Postgres, and paste the connection string and table name. Test connection runs a no-op query so a credential or firewall problem shows up immediately.
What you will be asked for
- Connection string, stored encrypted: The full postgres:// URI for the database, including user, password, host, port and database name. Add ?sslmode=require unless your host does not support TLS. Stored encrypted.
- 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, plus a cursor for paging past the offset ceiling |
| Record count | Exact: the total describes the filtered set |
Worth knowing first
- Your database must be reachable from the public internet. Requests come from Vercel, so allow-list its egress if your host supports it.
- Private, loopback and link-local addresses are refused before a socket opens, so a connection string pointing at localhost will not work by design.
- Sorting is by id only for now. Filtering supports the full documented grammar.
If something goes wrong
Host refused
Why: The host resolves to a private, loopback, link-local or carrier-grade NAT address, which is blocked to prevent requests reaching internal systems.
Fix: Use a publicly reachable host. A database on your laptop or inside a private network cannot be connected directly.
password authentication failed
Why: Wrong user or password, or the role is not allowed to log in from this host.
Fix: Check the credentials, and check your host's access rules allow connections from outside your network.
relation does not exist
Why: The table name is wrong, or the role cannot see the schema it lives in.
Fix: Use the table name without the schema prefix, and grant USAGE on the schema to the role.
Connection string must use the postgres:// scheme
Why: A different scheme was pasted, for example mysql:// or a bare host.
Fix: Use a full postgres:// or postgresql:// URI including user, password, host, port and database.