Skip to main content
Connect your own PostgreSQL or MySQL database and the agent can look up and update live records mid-call — check an appointment, confirm a balance, capture a request. Unlike the curated providers, a database has no pre-built actions: you discover its schema and map the exact queries you want as skills. Nothing runs that you didn’t author and approve.
Authenticate every request with a secret API key: Authorization: Bearer flowyte_sk_…. The kind is postgres or mysql.

How it fits together

1

Create a least-privilege database user

Generate the SQL to create a scoped user, then run it on your database — the agent never uses your admin credentials.
2

Test, then connect

Validate the credentials, then connect with them. They’re encrypted at rest and never echoed back.
3

Discover the schema and scope it

Introspect the database, then optionally block tables/columns the agent must never see.
4

Bind queries as skills

Map a read (or a scoped write) onto a skill — a frozen, parameterized statement the agent calls.

1. Generate a scoped database user

GET /integrations/{kind}/sql/scripts returns copy-paste SQL to create a least-privilege database user: a read-only role (SELECT only) and, if you need writes, a script scoped to only the tables your write skills touch — never blanket write. If you don’t pass a password, a strong one is generated and returned once.
curl "https://builder.flowyte.com/api/v1/integrations/postgres/sql/scripts?database=appdb&tables=appointments" \
  -H "Authorization: Bearer flowyte_sk_…"
# → { "data": { "readOnly": { … }, "write": { … }, "generatedPassword": "…" } }
Run the returned scripts on your database as an admin, then use the scoped user’s credentials below.

2. Test the connection

POST /integrations/{kind}/sql/test runs an ordered set of checks — reachability and TLS, authentication, reading the schema, a timed read probe, a read-only-session proof, and a live-call latency verdict — without storing anything. It always returns 200 with the check results and an overall ok flag; a host that resolves to a private, loopback, or metadata address is refused.
curl -X POST https://builder.flowyte.com/api/v1/integrations/postgres/sql/test \
  -H "Authorization: Bearer flowyte_sk_…" -H "Content-Type: application/json" \
  -d '{ "credentials": {
        "host": "db.example.com", "port": "5432", "database": "appdb",
        "user": "flowyte_ro", "password": "…", "sslmode": "verify-full"
      } }'
# → { "data": { "ok": true, "checks": [ … ] } }
sslmode must be require, verify-ca, or verify-fulldisable is refused at the connect boundary. Prefer verify-full and supply ca_pem when your database uses a private CA.

3. Connect

Pass the same credentials to the generic connect endpoint. The kind is postgres or mysql.
curl -X POST https://builder.flowyte.com/api/v1/integrations/postgres/connect \
  -H "Authorization: Bearer flowyte_sk_…" -H "Content-Type: application/json" \
  -d '{ "credentials": {
        "host": "db.example.com", "port": "5432", "database": "appdb",
        "user": "flowyte_ro", "password": "…", "sslmode": "verify-full"
      } }'
# → { "data": { "status": "connected" } }

4. Discover the schema and scope it

Introspect the database into a normalized schema, then read it (or search it) to find what to map:
curl -X POST https://builder.flowyte.com/api/v1/integrations/postgres/discover \
  -H "Authorization: Bearer flowyte_sk_…"

curl "https://builder.flowyte.com/api/v1/integrations/postgres/search?q=appointment%20status" \
  -H "Authorization: Bearer flowyte_sk_…"
Set data scoping to keep sensitive tables and columns out of reach — they disappear from the schema browser and are refused at bind time. Scoping is a privacy control you set per connection and it survives re-discovery.
curl -X PATCH https://builder.flowyte.com/api/v1/integrations/postgres/scoping \
  -H "Authorization: Bearer flowyte_sk_…" -H "Content-Type: application/json" \
  -d '{ "blockedTables": ["payments"], "blockedColumns": { "customers": ["ssn", "card_last4"] } }'

5. Bind a query as a skill

Map an operation onto a skill with a binding: a read filters on one indexed column; a write is a single-row insert or an update-by-unique-key. The binding compiles to a frozen, parameterized statement — the agent supplies the parameters and never sees raw SQL or the full schema. Writes land disabled for review, and columns you scoped out are rejected.
curl -X POST https://builder.flowyte.com/api/v1/agents/AGENT_ID/integrations/postgres/bindings \
  -H "Authorization: Bearer flowyte_sk_…" -H "Content-Type: application/json" \
  -d '{
        "toolName": "Look up an appointment",
        "operation": "appointments.read",
        "inputs": [ { "param": "caller_phone", "arg": "phone", "required": true } ],
        "projection": [
          { "path": ["appointment", "starts_at"], "leaf": "appointment_time" },
          { "path": ["appointment", "status"],    "leaf": "appointment_status" }
        ],
        "enabled": true
      }'
Prefer describing the goal instead? POST /agents/{id}/integrations/postgres/bindings/auto takes a plain-language goal and the AI assistant proposes the binding for you to review.

In the API

ActionEndpointScope
Generate setup scriptsGET /integrations/{kind}/sql/scriptsintegrations:read
Test a connectionPOST /integrations/{kind}/sql/testintegrations:write
ConnectPOST /integrations/{kind}/connectintegrations:write
Discover the schemaPOST /integrations/{kind}/discoverintegrations:write
Search / read the schemaGET /integrations/{kind}/search · GET /integrations/{kind}/schemaintegrations:read
Get / set data scopingGET · PATCH /integrations/{kind}/scopingintegrations:read · integrations:write
Bind a query as a skillPOST /agents/{agentId}/integrations/{kind}/bindingsskills:write
DisconnectDELETE /integrations/{kind}integrations:write
Binding edits the draft. Publish so live callers get real data.
Full walkthrough: Connect a SQL database.