# Run database query

`POST https://api.instacloud.com/projects/{projectId}/database/query`

**Token scope:** `account` · `org` · `project` — read-only tokens refused (not a GET).

Run one SQL statement with the service credential (full privileges — the gate and audit are a record, not a permission boundary). The audit log records a statement hash and parameter count, never SQL text or values. Gated — db.query. May wake a suspended database.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `branch` | query | `string` | no | Branch name (defaults to the project's default branch) |
| `group` | query | `string` | no | postgres service name (default: the sole postgres service) |
| `database` | query | `string` | no | database on the instance (default: the connection-string database) |
| `projectId` | path | `string` | yes |  |

## Request body (application/json)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `sql` | `string` | yes |  |
| `params` | `any[]` | no | positional parameter values for $1..$n — audited as a count, never as values |
| `maxRows` | `integer` | no |  |

## Response 200

Default Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `columns` | `object[]` | yes |  |
| `columns.name` | `string` | yes |  |
| `columns.dataTypeID` | `integer` | yes |  |
| `rows` | `any[][]` | yes | rows as positional cells — duplicate column names stay distinct; numeric/int8 arrive as strings |
| `rowCount` | `integer` | yes |  |
| `truncated` | `boolean` | yes | true when maxRows clipped the result — narrow with WHERE/LIMIT |
| `queryId` | `null \| null` | yes | reserved for future cancellation |

## Response 202

Default Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | `"approval_required"` | no |  |
| `approvalId` | `string` | no |  |
| `action` | `string` | no | the gated action, or a comma-joined compound set — prefer `actions` |
| `actions` | `string[]` | no | every capability this approval covers |
| `message` | `string` | no |  |
| `url` | `string` | no | the console page where a project admin reviews this request |
| `nextActions` | `object[]` | no |  |
| `nextActions.op` | `string` | yes | Neutral logical action id, e.g. "service.add" — NOT an operationId or a CLI/MCP tool name; each client maps it to its own surface. |
| `nextActions.reason` | `string` | yes | Natural-language, human/LLM-facing "why do this now". |
| `nextActions.args` | `object` | no | Suggested, flat named arguments; "<placeholder>"s where a value is unknown. |
| `nextActions.gated` | `boolean` | no | True if the action passes a governance gate. |

## Response 400

Default Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | `string` | yes |  |

## Response 403

Default Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | `string` | yes |  |

## Response 404

Default Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | `string` | yes |  |

## Response 409

code public_access_closed: the database's public access is closed and the console has no private lane on this deployment yet

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | `string` | yes |  |
| `code` | `string` | no | stable machine-readable reason, e.g. private_lane_disabled, private_lane_unavailable_in_region, public_access_closed, credential_change_in_progress |

## Response 502

Default Response

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | `string` | yes |  |
