Access Rules
Manage role-based table and column access rules
Create, list, update, and delete access rules that control which tables and columns each role can see. Requires the access_rules:manage permission (owner or admin role).
Plan availability
Access Rules is available on Pro, Premium, and Enterprise plans.
Endpoints
| Method | Endpoint | Permission | Description |
|---|---|---|---|
GET | /access-rules | access_rules:manage | List all rules for the current tenant |
POST | /access-rules | access_rules:manage | Create a rule |
PUT | /access-rules/{rule_id} | access_rules:manage | Update a rule's columns |
DELETE | /access-rules/{rule_id} | access_rules:manage | Delete a rule |
List rules
GET /access-rulesReturns all access rules for the current tenant, ordered by role, schema, table, and effect.
Response
[
{
"id": "a1b2c3d4-...",
"role": "analyst",
"schema_name": "mydb",
"table_name": "users",
"columns": ["id", "name", "email"],
"effect": "allow",
"warnings": []
}
]Create a rule
POST /access-rulesRequest body
{
"role": "analyst",
"schema_name": "mydb",
"table_name": "users",
"columns": ["id", "name", "email"],
"effect": "allow"
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
role | string | yes | — | Target role (operator, analyst, or viewer) |
schema_name | string | yes | — | MySQL schema name |
table_name | string | yes | — | MySQL table name |
columns | array | no | ["*"] | Column list (see column patterns) |
effect | string | no | "allow" | "allow" or "deny" |
Response (201)
{
"id": "a1b2c3d4-...",
"role": "analyst",
"schema_name": "mydb",
"table_name": "users",
"columns": ["email", "id", "name"],
"effect": "allow",
"warnings": []
}Columns are normalized: duplicates are removed, values are sorted alphabetically, and ["*"] is simplified to a single wildcard entry.
Collision warnings
If a conflicting rule already exists (e.g., creating an allow rule when a deny rule exists for the same role and table), the response includes warnings:
{
"id": "a1b2c3d4-...",
"role": "analyst",
"schema_name": "mydb",
"table_name": "users",
"columns": ["id", "name", "email"],
"effect": "allow",
"warnings": [
{
"message": "Conflicting deny rule exists for analyst on mydb.users (columns: [\"ssn\", \"credit_card\"]). Deny rules take priority over allow rules.",
"conflicting_rule_id": "e5f6g7h8-...",
"conflicting_effect": "deny"
}
]
}Errors
| Status | Reason |
|---|---|
| 409 | A rule with the same role, schema, table, and effect already exists |
| 422 | Invalid role, schema/table name, or empty columns list |
Update a rule
PUT /access-rules/{rule_id}Updates the columns for an existing rule. The role, schema, table, and effect are immutable — to change them, delete the rule and create a new one.
Request body
{
"columns": ["id", "name", "email", "created_at"]
}| Field | Type | Required | Description |
|---|---|---|---|
columns | array | yes | New column list |
Response (200)
Returns the updated rule with the same shape as the create response, including any collision warnings.
Errors
| Status | Reason |
|---|---|
| 404 | Rule not found |
| 422 | Empty columns list |
Delete a rule
DELETE /access-rules/{rule_id}Deletes an access rule. Returns 204 No Content on success.
Errors
| Status | Reason |
|---|---|
| 404 | Rule not found |
Schemas
AccessRuleResponse
| Field | Type | Description |
|---|---|---|
id | string | Rule UUID |
role | string | Target role |
schema_name | string | MySQL schema name |
table_name | string | MySQL table name |
columns | array | Column list |
effect | string | "allow" or "deny" |
warnings | array | Collision warnings (empty if none) |
CollisionWarning
| Field | Type | Description |
|---|---|---|
message | string | Human-readable description of the conflict |
conflicting_rule_id | string | UUID of the conflicting rule |
conflicting_effect | string | Effect of the conflicting rule ("allow" or "deny") |