Access policies API
Create, read, update, and delete the access policies that route just-in-time access requests to approval paths — with the endpoints, schema, authentication, errors, and worked examples you need to imp
The Access Policies API gives you programmatic control over how just-in-time access requests are evaluated and approved. Each access policy is a rule that matches on the requestor (who is asking) and the resource (what they want), then routes matching requests down an approval path — manual approval, auto-approval for on-call engineers, standing access, or an outright deny.
Use this API to manage policies as code: read your current rules, add or change a single rule by name, or replace your whole configuration in one request. For the product concepts, evaluation order, and the full filter reference, see Configuring access policies.
Base URL and authentication
Every endpoint lives under your organization's base URL, which includes your organization slug (orgId):
https://api.p0.app/o/{orgId}All requests require a bearer token. See Authenticating with the P0 API to get one — from a Google Cloud service-account token (recommended), the P0 CLI, or a legacy API key — and pass it in the Authorization header:
curl -H "Authorization: Bearer $P0_API_TOKEN" \
https://api.p0.app/o/{orgId}/policyFor the base URL, authentication, and permissions shared by all P0 APIs, see the P0 API overview.
Permissions
Read policies (GET)
policies.version.read
Owner, Manager
Change policies (POST, PUT, DELETE)
policies.version.add
Owner
A token's privileges come from the P0 role of its identity, so grant each identity the least privilege it needs. A legacy API key carries the full Owner role and can call every endpoint on this page. A caller who is authenticated but lacks the permission — for example, a Manager calling a write endpoint — gets 403 Forbidden, not 401.
Two ways to manage policies
Your organization has one active policy configuration — a PolicyConfig, which is an object with a rules array of individual Policy rules. This API exposes that configuration two ways:
A single rule at a time, addressed by its
name, under/policy/name/{name}. UsePOST,PUT, andDELETEto add, change, or remove one rule without touching the rest. This is the most direct way to automate incremental changes.The whole configuration at once, under
/policy.POSTreplaces the entire rule set. Use this for config-as-code workflows that manage all rules together.
The two shapes carry different bodies: the /policy/name/{name} endpoints send and receive a single Policy, while POST /policy sends a PolicyConfig wrapped with a currentVersion for optimistic concurrency.
P0 keeps a version history of the configuration. Every write — whether through /policy/name/{name} or POST /policy — creates a new configuration version. A single-rule write still versions the whole configuration; it just leaves the other rules unchanged. To read the active configuration and the version you need for optimistic concurrency, get latest.
Rule names match case-insensitively. Creating Engineering-AWS when engineering-aws already exists returns 409 Conflict, and a GET by either casing finds the same rule.
Endpoints
Returns every document in the organization's policy store, each with its rules and metadata. The result is unordered, and it includes more than version snapshots: the active-configuration pointer is returned with id: "latest" (and carries a version), and an options document is returned with id: "_default_" and no rules. To read the active configuration and its version, get latest instead (GET /policy/latest).
The documents in the organization's policy store.
The token is missing or invalid, or it is valid but belongs to an identity that is not a member of your P0 organization, so it holds no P0 role. Add the identity — for example, a service account's email — as a member in Role-Based Access Control.
The token is valid and the identity is a member of your P0 organization, but it lacks the required permission — for example, a Manager calling a write endpoint, which requires the Owner role.
GET /o/demo-org/policy HTTP/1.1
Host: api.p0.app
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"policies": [
{
"rules": [
{
"name": "engineering-aws-readonly",
"disabled": true,
"requestor": {
"type": "any"
},
"resource": {
"type": "any"
},
"approval": [
{
"type": "p0",
"options": {
"allowOneParty": true,
"breakGlassApprover": true,
"requireReason": true,
"requireDuration": true,
"requirePreapproval": true
}
}
]
}
],
"id": "text",
"version": "text",
"createdDate": "2026-01-01T00:00:00.000Z"
}
]
}Replaces the entire active policy configuration with a new set of rules and creates a new version. Use currentVersion for optimistic concurrency: pass the version from GET /policy/latest (or from a prior write's response), and the request fails with 409 if the configuration changed in the meantime.
A request to replace the active policy configuration.
The version of the configuration you are editing. If it no longer matches the active configuration, the request fails with 409 so you can reload and reapply your edits.
The new policy configuration, including its version ID.
The request body failed validation — for example, a name that contains a slash, a name that does not match the URL, an unknown service, a filter with a non-string pattern or an invalid key, or any unknown field (policy objects reject unknown properties). The response body describes the problem.
The token is missing or invalid, or it is valid but belongs to an identity that is not a member of your P0 organization, so it holds no P0 role. Add the identity — for example, a service account's email — as a member in Role-Based Access Control.
The token is valid and the identity is a member of your P0 organization, but it lacks the required permission — for example, a Manager calling a write endpoint, which requires the Owner role.
The change conflicts with the current state — for example, a rule with the given name already exists, more than one rule matches the given name, or the supplied currentVersion no longer matches the active configuration.
A filter pattern (or an agentic subjectPattern) is not a valid regular expression, or is unsafe because it is subject to catastrophic backtracking.
POST /o/demo-org/policy HTTP/1.1
Host: api.p0.app
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 307
{
"currentVersion": "text",
"policy": {
"rules": [
{
"name": "engineering-aws-readonly",
"disabled": true,
"requestor": {
"type": "any"
},
"resource": {
"type": "any"
},
"approval": [
{
"type": "p0",
"options": {
"allowOneParty": true,
"breakGlassApprover": true,
"requireReason": true,
"requireDuration": true,
"requirePreapproval": true
}
}
]
}
]
}
}{
"policy": {
"rules": [
{
"name": "engineering-aws-readonly",
"disabled": true,
"requestor": {
"type": "any"
},
"resource": {
"type": "any"
},
"approval": [
{
"type": "p0",
"options": {
"allowOneParty": true,
"breakGlassApprover": true,
"requireReason": true,
"requireDuration": true,
"requirePreapproval": true
}
}
]
}
],
"version": "text"
}
}Returns a stored policy configuration by its ID. Pass a version ID to read that snapshot, or the literal latest to read the active configuration together with its version.
A policy configuration version ID, returned as version by the create endpoint. Pass the literal latest to read the active configuration together with its version — this is the only way to read the active configuration and the version you need for optimistic concurrency.
latestThe requested policy configuration.
The token is missing or invalid, or it is valid but belongs to an identity that is not a member of your P0 organization, so it holds no P0 role. Add the identity — for example, a service account's email — as a member in Role-Based Access Control.
The token is valid and the identity is a member of your P0 organization, but it lacks the required permission — for example, a Manager calling a write endpoint, which requires the Owner role.
No policy matches the given name or version ID.
GET /o/demo-org/policy/{policyId} HTTP/1.1
Host: api.p0.app
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"policy": {
"rules": [
{
"name": "engineering-aws-readonly",
"disabled": true,
"requestor": {
"type": "any"
},
"resource": {
"type": "any"
},
"approval": [
{
"type": "p0",
"options": {
"allowOneParty": true,
"breakGlassApprover": true,
"requireReason": true,
"requireDuration": true,
"requirePreapproval": true
}
}
]
}
],
"id": "text",
"version": "text",
"createdDate": "2026-01-01T00:00:00.000Z"
}
}Returns a single policy rule from the active configuration by its name.
The policy rule's unique name. Cannot contain a forward slash (/) or backslash (\). Names match case-insensitively, so Engineering-AWS and engineering-aws refer to the same rule.
engineering-aws-readonlyThe requested policy rule.
A single access-control policy rule.
A unique, human-readable name for the rule. Cannot contain / or \.
engineering-aws-readonlyIf true, P0 skips this rule during evaluation. Defaults to false.
Matches who is making the request.
Matches which resource the request targets.
The token is missing or invalid, or it is valid but belongs to an identity that is not a member of your P0 organization, so it holds no P0 role. Add the identity — for example, a service account's email — as a member in Role-Based Access Control.
The token is valid and the identity is a member of your P0 organization, but it lacks the required permission — for example, a Manager calling a write endpoint, which requires the Owner role.
No policy matches the given name or version ID.
The change conflicts with the current state — for example, a rule with the given name already exists, more than one rule matches the given name, or the supplied currentVersion no longer matches the active configuration.
GET /o/demo-org/policy/name/{name} HTTP/1.1
Host: api.p0.app
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
"name": "engineering-aws-readonly",
"disabled": true,
"requestor": {
"type": "any"
},
"resource": {
"type": "any"
},
"approval": [
{
"type": "p0",
"options": {
"allowOneParty": true,
"breakGlassApprover": true,
"requireReason": true,
"requireDuration": true,
"requirePreapproval": true
}
}
]
}Adds a single named rule to the active configuration and creates a new configuration version. The name in the body must match the name in the path. Fails with 409 if a rule with that name already exists — use PUT to change an existing rule.
The policy rule's unique name. Cannot contain a forward slash (/) or backslash (\). Names match case-insensitively, so Engineering-AWS and engineering-aws refer to the same rule.
engineering-aws-readonlyA single access-control policy rule.
A unique, human-readable name for the rule. Cannot contain / or \.
engineering-aws-readonlyIf true, P0 skips this rule during evaluation. Defaults to false.
Matches who is making the request.
Matches which resource the request targets.
The created policy rule.
A single access-control policy rule.
A unique, human-readable name for the rule. Cannot contain / or \.
engineering-aws-readonlyIf true, P0 skips this rule during evaluation. Defaults to false.
Matches who is making the request.
Matches which resource the request targets.
The request body failed validation — for example, a name that contains a slash, a name that does not match the URL, an unknown service, a filter with a non-string pattern or an invalid key, or any unknown field (policy objects reject unknown properties). The response body describes the problem.
The token is missing or invalid, or it is valid but belongs to an identity that is not a member of your P0 organization, so it holds no P0 role. Add the identity — for example, a service account's email — as a member in Role-Based Access Control.
The token is valid and the identity is a member of your P0 organization, but it lacks the required permission — for example, a Manager calling a write endpoint, which requires the Owner role.
The change conflicts with the current state — for example, a rule with the given name already exists, more than one rule matches the given name, or the supplied currentVersion no longer matches the active configuration.
A filter pattern (or an agentic subjectPattern) is not a valid regular expression, or is unsafe because it is subject to catastrophic backtracking.
POST /o/demo-org/policy/name/{name} HTTP/1.1
Host: api.p0.app
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 260
{
"name": "engineering-aws-readonly",
"disabled": true,
"requestor": {
"type": "any"
},
"resource": {
"type": "any"
},
"approval": [
{
"type": "p0",
"options": {
"allowOneParty": true,
"breakGlassApprover": true,
"requireReason": true,
"requireDuration": true,
"requirePreapproval": true
}
}
]
}{
"name": "engineering-aws-readonly",
"disabled": true,
"requestor": {
"type": "any"
},
"resource": {
"type": "any"
},
"approval": [
{
"type": "p0",
"options": {
"allowOneParty": true,
"breakGlassApprover": true,
"requireReason": true,
"requireDuration": true,
"requirePreapproval": true
}
}
]
}Replaces an existing named rule in the active configuration and creates a new configuration version. The name in the body must match the name in the path. Fails with 404 if no rule with that name exists — use POST to create one.
The policy rule's unique name. Cannot contain a forward slash (/) or backslash (\). Names match case-insensitively, so Engineering-AWS and engineering-aws refer to the same rule.
engineering-aws-readonlyA single access-control policy rule.
A unique, human-readable name for the rule. Cannot contain / or \.
engineering-aws-readonlyIf true, P0 skips this rule during evaluation. Defaults to false.
Matches who is making the request.
Matches which resource the request targets.
The updated policy rule.
A single access-control policy rule.
A unique, human-readable name for the rule. Cannot contain / or \.
engineering-aws-readonlyIf true, P0 skips this rule during evaluation. Defaults to false.
Matches who is making the request.
Matches which resource the request targets.
The request body failed validation — for example, a name that contains a slash, a name that does not match the URL, an unknown service, a filter with a non-string pattern or an invalid key, or any unknown field (policy objects reject unknown properties). The response body describes the problem.
The token is missing or invalid, or it is valid but belongs to an identity that is not a member of your P0 organization, so it holds no P0 role. Add the identity — for example, a service account's email — as a member in Role-Based Access Control.
The token is valid and the identity is a member of your P0 organization, but it lacks the required permission — for example, a Manager calling a write endpoint, which requires the Owner role.
No policy matches the given name or version ID.
The change conflicts with the current state — for example, a rule with the given name already exists, more than one rule matches the given name, or the supplied currentVersion no longer matches the active configuration.
A filter pattern (or an agentic subjectPattern) is not a valid regular expression, or is unsafe because it is subject to catastrophic backtracking.
PUT /o/demo-org/policy/name/{name} HTTP/1.1
Host: api.p0.app
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 260
{
"name": "engineering-aws-readonly",
"disabled": true,
"requestor": {
"type": "any"
},
"resource": {
"type": "any"
},
"approval": [
{
"type": "p0",
"options": {
"allowOneParty": true,
"breakGlassApprover": true,
"requireReason": true,
"requireDuration": true,
"requirePreapproval": true
}
}
]
}{
"name": "engineering-aws-readonly",
"disabled": true,
"requestor": {
"type": "any"
},
"resource": {
"type": "any"
},
"approval": [
{
"type": "p0",
"options": {
"allowOneParty": true,
"breakGlassApprover": true,
"requireReason": true,
"requireDuration": true,
"requirePreapproval": true
}
}
]
}Removes a single named rule from the active configuration and creates a new configuration version.
The policy rule's unique name. Cannot contain a forward slash (/) or backslash (\). Names match case-insensitively, so Engineering-AWS and engineering-aws refer to the same rule.
engineering-aws-readonlyThe rule was deleted.
No content
The token is missing or invalid, or it is valid but belongs to an identity that is not a member of your P0 organization, so it holds no P0 role. Add the identity — for example, a service account's email — as a member in Role-Based Access Control.
The token is valid and the identity is a member of your P0 organization, but it lacks the required permission — for example, a Manager calling a write endpoint, which requires the Owner role.
No policy matches the given name or version ID.
The change conflicts with the current state — for example, a rule with the given name already exists, more than one rule matches the given name, or the supplied currentVersion no longer matches the active configuration.
DELETE /o/demo-org/policy/name/{name} HTTP/1.1
Host: api.p0.app
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
No content
Policy schema
A Policy has three required parts and two optional fields:
name
string
No
A unique, human-readable name. Cannot contain / or \. Required to address the rule under /policy/name/{name}.
disabled
boolean
No
If true, P0 skips the rule during evaluation. Defaults to false.
requestor
RequestorRule
Yes
Matches who is making the request: any, user, group, or agentic.
resource
ResourceRule
Yes
Matches the target: any or a specific integration.
approval
ApprovalRule[]
Yes
The approval path. At least one non-break-glass approver is required. A single deny rule denies all matching requests.
Examples
The following examples assume your bearer token is in the P0_API_TOKEN environment variable and your organization slug is your-org. See Authenticating with the P0 API to get a token.
Read a single rule
The response is the matching Policy:
Create a rule
Add a rule by POSTing a Policy to /policy/name/{name}. The name in the body must match the name in the URL. This example routes the engineering group's non-admin AWS permission-set requests to your Security Reviewers, and requires a reason:
A successful create returns 201 Created and echoes the stored rule. If a rule with that name already exists, the request fails with 409 Conflict — use PUT to change it instead.
Update a rule
PUT replaces an existing rule. This example changes the approver to the SRE directory group and lets on-call engineers self-approve:
A successful update returns 200 OK with the stored rule. If no rule with that name exists, the request fails with 404 Not Found — use POST to create it.
Delete a rule
A successful delete returns 204 No Content with an empty body.
Read the active configuration
To read the active configuration with the version you need for a concurrent-safe write, get the special latest configuration:
The response wraps the active configuration, its version, and metadata:
Replace the whole configuration
POST /policy replaces every rule at once and creates a new configuration version. To avoid overwriting a concurrent change, pass the version from GET /policy/latest as currentVersion. Submit the new configuration:
The response contains the stored configuration and the new version:
If the active configuration changed since you read currentVersion, the request fails with 409 Conflict and the message "Policies have changed since your edits. Please reload rules and apply these edits again." Reload with GET /policy/latest, reapply your edits, and retry.
Errors
400 Bad Request
The body failed schema validation — for example, the name contains a slash, the name in the body does not match the URL, service is not a known integration, a filter's key is invalid, or the body includes an unknown field. The response describes the problem.
401 Unauthorized
The token is missing or invalid, or it is valid but belongs to an identity that is not a member of your P0 organization (it holds no P0 role). Add the identity — for example, a service account's email — as a member in Role-Based Access Control. See Authenticating with the P0 API.
403 Forbidden
The token is valid and the identity is a member, but it lacks the required permission — for example, a Manager calling a write endpoint.
404 Not Found
No rule matches the name, or no configuration matches the policyId.
409 Conflict
A rule with that name already exists (on create), more than one rule matches the name (on get, update, or delete), or the supplied currentVersion no longer matches the active configuration.
422 Unprocessable Entity
A filter pattern (or an agentic subjectPattern) is not a valid regular expression, or is unsafe because it is subject to catastrophic backtracking.
Related
Configuring access policies — the full rule reference: requestor, resource, filter, and approval types, plus evaluation order.
Configure your first access policy — a hands-on tutorial for building your first policy in Policy Studio.
Agentic access policies — the
agenticrequestor rule for AI agents.Authenticating with the P0 API — get a bearer token to authenticate these requests.
P0 API overview — the base URL, authentication, and permissions shared by all P0 APIs.
Last updated