Unified Policy API
The Customer Portal's source-agnostic dispatcher over the two legacy policy families, at /api/v1/unified-policies, as it answers in v11.0.0.
The unified API reads and writes the legacy system policies (System Policy API) and tenant policies (Tenant Policy API). In v11 both are read-only and decide nothing. Its writes are refused with the underlying API's 409 LEGACY_POLICY_WRITE_FROZEN, and its reads are removed with the portal's legacy Policies page; to export your rows, use the read routes of the two APIs above. The portal's policy authoring surface in v11 is Policy Authoring, over typed policy documents; see Typed Policy Authoring.
The Customer Portal and this dispatcher are Enterprise. The dispatcher is not in the published OpenAPI specs (it is served by the portal, not a policy service), so this page is its reference.
How the dispatcher works
The unified API does not evaluate or store anything itself. Every policy in a response carries a source field ("static" or "dynamic"), and every id-addressed call is resolved to the family that owns the id, by the same lookup for reads and writes. Resolution is fail-closed: an id on exactly one side is dispatched there; an id on neither answers 404; a side that cannot be reached answers 502 and nothing is written.
Read endpoints
Removed in v11, with the portal's legacy Policies page they served. Listed here for readers of v10.x integrations:
| Method & Path | Purpose |
|---|---|
GET /api/v1/unified-policies | List policies from both families, source-tagged, paginated |
GET /api/v1/unified-policies/summary | Counts by source, tier, category and severity |
GET /api/v1/unified-policies/effective | The rows with overrides applied, the way v10.x combined them |
GET /api/v1/unified-policies/{id} | One policy from whichever family owns it |
List, summary and effective responses carry partial: true and source_errors when one family could not be reached, so a missing side is reported rather than silently dropped.
| Parameter | Default | Notes |
|---|---|---|
source | all | all, static, or dynamic |
enabled | — | Filter by enabled status |
category | — | Category filter, applied per family |
tier | — | system, organization, or tenant |
type | — | Policy type filter (tenant policies) |
page | 1 | Page number |
page_size | 20 | Max 100 |
Write endpoints
| Method & Path | Dispatches to | In v11 |
|---|---|---|
POST /api/v1/unified-policies | the family named by source | 409 LEGACY_POLICY_WRITE_FROZEN |
PUT /api/v1/unified-policies/{id} | the family that owns the id | 409 LEGACY_POLICY_WRITE_FROZEN |
DELETE /api/v1/unified-policies/{id} | the family that owns the id | 409 LEGACY_POLICY_WRITE_FROZEN |
POST /api/v1/unified-policies/{id}/toggle | the family that owns the id | 409 LEGACY_POLICY_WRITE_FROZEN |
POST|GET|DELETE /api/v1/unified-policies/{id}/override | the Agent's legacy per-policy override, system policies only | legacy: the v11 engine does not read it; see Policy overrides |
The dispatcher passes an error from the family it dispatched to through unchanged, so a refused write reaches the caller with the same status and body as a direct call:
{
"error": {
"code": "LEGACY_POLICY_WRITE_FROZEN",
"message": "The legacy policy tables are read-only in v11: migrations/core/172 revoked write access from the application role, and this endpoint writes them. Author policies through the typed authoring route at /api/v1/typed-policies instead. Reads on this endpoint are unaffected."
}
}
The dispatcher's own refusals are unchanged: a create with a missing or unknown source answers 400, and an override request against a tenant policy answers 400.
Related
- Typed Policy Authoring: the v11 authoring surface
- Shipped Policy Posture
- System Policy API and Tenant Policy API: the families this dispatches to
- Overrides API
