---
title: "updatePolicyProfile"
description: "Update a policy profile"
canonical: "https://pgbeam.com/docs/ts-sdk/policies/updatePolicyProfile"
last-updated: "2026-09-14T21:29:34.000Z"
---

# updatePolicyProfile

> Update a policy profile

URL: https://pgbeam.com/docs/ts-sdk/policies/updatePolicyProfile

Updates a policy profile. Changes hot-reload to active agent sessions.

## Usage

## Parameters

Parameter

Type

Required

Description

pathParams.project\_id

`string`

Yes

Unique project identifier (prefixed, e.g. prj\_xxx).

pathParams.policy\_id

`string`

Yes

Unique policy profile identifier (prefixed, e.g. pol\_xxx).

body.name

`string`

Yes

Human-readable name for the policy profile.

body.access\_mode

`"read_only" \| "read_write"`

No

read\_only blocks all data and schema mutations.

body.statement\_rules

`StatementRules`

No

Per-statement-kind allow/deny lists. Empty allow means all kinds permitted by the access mode.

body.table\_allowlist

`string[]`

No

If non-empty, only these relations are reachable. A bare entry grants the public schema only; list another schema in full, as in billing.orders.

body.table\_denylist

`string[]`

No

Relations explicitly blocked. A bare entry blocks that relation in every schema.

body.masking\_rules

`MaskingRule[]`

No

Column masking rules applied to query results.

body.budget\_queries\_per\_hour

`number`

No

Max queries per rolling hour window. 0 means unlimited.

body.budget\_queries\_per\_day

`number`

No

Max queries per day window. 0 means unlimited.

body.max\_rows

`number`

No

Max rows returned per query. 0 means unlimited.

body.statement\_timeout\_ms

`number`

No

Upstream statement timeout for agent sessions. 0 uses the project default.

body.row\_filters

`RowFilter[]`

No

Per-relation row filters ANDed into agent reads.

body.write\_mode

`"normal" \| "rollback" \| "sandbox"`

No

How writes are handled. normal commits, rollback auto-rolls back, sandbox routes to an ephemeral branch.

body.approval\_mode

`"off" \| "writes" \| "ddl" \| "all"`

No

Which statement classes require human approval before execution.

body.approval\_auto\_max\_rows

`number`

No

Statements touching at most this many rows are auto-approved. 0 means none.

body.approval\_timeout\_seconds

`number`

No

How long a held statement waits for a decision before expiring.

body.migration\_safety

`"off" \| "warn" \| "block"`

No

Migration safety mode. warn surfaces findings, block refuses unsafe DDL.

body.egress\_bytes\_per\_day

`number`

No

Per-day egress budget in bytes. 0 means unlimited.

body.max\_affected\_rows

`number`

No

Hard cap on rows a single write (INSERT/UPDATE/DELETE) may affect. A write whose affected-row count would exceed this is executed inside a transaction, checked, and rolled back so nothing persists, then blocked. Enforced independently of human approval. 0 means unlimited.

body.content\_scan\_mode

`"off" \| "annotate" \| "block"`

No

Result-content scanning, enforced on the data-plane relay path: values on their way out to an agent are checked for instruction-shaped content (stored prompt injection). off scans nothing and costs nothing. annotate scans and forwards every value unchanged, recording what it found. block is accepted and scans exactly as annotate does, but refusing the statement is not implemented yet, so today it also forwards every value. No mode drops or rewrites a row. A flagged statement records one content\_flagged audit entry naming the columns, the techniques and whether the scan covered the whole result, alongside the proxy's own metrics and logs; the entry carries no value from the row itself, and the webhook stream is not wired to it yet. A finding the structural detectors report at high confidence also raises an anomaly alert, at most one per credential per hour; lower-confidence findings stay in the audit trail. Values the scan cannot read (binary-format columns, columns this profile masks, and anything past content\_scan\_max\_bytes) are counted as unscanned rather than reported clean. A proxy build older than result-content scanning ignores this field.

body.content\_scan\_max\_bytes

`number`

No

Byte budget for one statement's content scan, spanning all values in the result. Values past it are reported unscannable rather than skipped quietly. The budget covers a whole statement, so the statements of one simple-query batch share it rather than each getting a fresh allowance. 0 uses the scanner default (4 MiB), which covers an interactive result set and deliberately does not cover a bulk export.

## Response

`Promise<PolicyProfile>`: updated policy profile.

## Example

## Errors

Status

Description

400

The request was rejected. `code` is `INVALID_INPUT`, and `errors` names the offending fields when the failure was a validation one.

401

Missing or invalid authentication. `code` is `UNAUTHORIZED`.

403

The caller is authenticated but not allowed to perform this operation. `code` is `FORBIDDEN` when the caller's role is insufficient, and `PLAN_LIMIT_REACHED` when the organization's plan is what stands in the way. The two are answered differently, so branch on the code rather than the status.

404

The resource does not exist, or the caller is not entitled to know that it does. `code` is `NOT_FOUND`.

412

The `If-Match` entity tag does not match the current representation, so the resource changed after the read this write was based on. Nothing was modified. `code` is `PRECONDITION_FAILED`. Re-read the resource, re-apply the change, and retry with the new tag.

413

The request body exceeds the 2 MB limit. `code` is `PAYLOAD_TOO_LARGE`.

415

The request body is not JSON, or carries a body without declaring a Content-Type. `code` is `UNSUPPORTED_MEDIA_TYPE`.

429

Rate limited. `code` is `RATE_LIMITED`.

500

The request failed for a reason on our side. `code` is `INTERNAL_ERROR`. Quote `request_id` when reporting it.