ProjectX Policy
The decision point and what feeds it: Authorize, Simulate, WhoCan and WhatCan, the tenancy hierarchy, roles, grants and policy packs. Every other service in the platform is a client of the four decision endpoints, and a customer auditing us is entitled to read the shape of the questions we ask about them.
57 operations · https://api.projectx.dev
Generated from the checked-in OpenAPI document for this service. The document itself is the authority, and it is what a generated client is built from.
entitlement 2
- POST
/v1/authorize:what-canRequiresiam:entitlement:readEverything one principal can reach
The forward query an entitlement review and an offboarding sweep both start from.
- Body
- WhatCanRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/authorize:who-canRequiresiam:entitlement:readWho can do this to this resource
Computed on every call rather than stored, because a cached answer to a security question is a wrong answer. `truncated` says when the list is a sample.
- Body
- WhoCanRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
grant 9
- POST
/v1/iam/access-requestsRequiresiam:grant:requestAsk for a time-boxed elevation
Needs an approver who is not the requester, and lapses on its own.
- Body
- AccessRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/iam/break-glassRequiresiam:grant:break_glassTake emergency access
Granted immediately and reviewed afterwards whether or not it was used. The review is the control: break-glass nobody looks at is standing access with a dramatic name.
- Body
- BreakGlassRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/iam/break-glass/{id}/reviewRequiresiam:grant:approveRecord the after-the-fact review of an emergency grant
What was done under it is in the audit chain; this records that somebody read it.
- Body
- BreakGlassReview
Parameters (3)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- GET
/v1/iam/break-glass/reviewsRequiresiam:grant:listEmergency grants still awaiting review
The queue that makes break-glass a control rather than a name. A grant appears here whether or not it was ever used.
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/iam/grantsRequiresiam:grant:listList grants
Expired grants are withheld unless asked for, because a review of who has access should not be buried in a list of who used to.
Parameters (5)
principal· query — Only grants held by this principal URN.kind· query — standing, elevation or break_glass.state· query — pending, active, expired, revoked or rejected.include_expired· query — Set to `true` to include grants that have lapsed.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/iam/grantsRequiresiam:grant:createCreate a standing grant
The kind is set by the route rather than by the body, so a caller cannot ask for break-glass at a standing grant’s ceiling.
- Body
- GrantRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- DELETE
/v1/iam/grants/{id}Requiresiam:grant:revokeRevoke a grant before it expires
The grant record is kept, revoked, so an access review can still see it was held.
Parameters (3)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/iam/grants/{id}/approveRequiresiam:grant:approveApprove a pending grant
`ttl_seconds` lets an approver grant less time than was asked for. An approver who can only say yes or no will say yes.
- Body
- GrantApproval
Parameters (3)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/iam/grants/{id}/rejectRequiresiam:grant:approveRefuse a pending grant
- Body
- GrantRejection
Parameters (3)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
organization 2
- GET
/v1/organizationsRequiresplatform:organization:readList organizations in the tenant
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/organizationsRequiresplatform:organization:createCreate an organization inside the tenant
- Body
- CreateOrganizationRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
pdp 3
- POST
/v1/authorizeRequiresplatform:pdp:authorizeAsk whether a principal may take an action on a resource
The one decision endpoint every other service in the platform calls. Unaudited on purpose: the caller writes the audit event for the action the decision was about, and a second event here would double the platform’s audit volume to record the same fact.
- Body
- AuthorizeRequest
- Returns
- AuthorizeResponse
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/authorize:batchRequiresplatform:pdp:authorizeAsk many authorization questions in one call
Answered in order, one decision per request. What a console uses to decide which of forty buttons to render enabled.
- Body
- AuthorizeBatchRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/iam/authorizeRequiresplatform:pdp:authorizeAsk whether a principal may take an action on a resource
The documented alias of `/v1/authorize`. Same handler, so the two paths cannot drift.
- Body
- AuthorizeRequest
- Returns
- AuthorizeResponse
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
policy 11
- POST
/v1/authorize:simulateRequiresiam:policy:simulateEvaluate a decision without taking the action
Returns every policy considered and whether it matched, which is what makes a policy editor able to explain a denial rather than merely report one.
- Body
- SimulateRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- GET
/v1/iam/permissionsRequiresiam:policy:listThe permission catalog, grouped by pillar
Frozen in code rather than configured per tenant, so a permission means the same thing everywhere. A role naming a permission that is not here is refused, which is what stops a role appearing to grant something nothing checks.
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/iam/policiesRequiresiam:policy:listList policies
Parameters (2)
environment· query — draft, staging or published. Absent means every environment.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/iam/policies:dry-runRequiresiam:policy:simulateReport what a promotion would change
Names every change and whether any of them broadens access. Nothing is written.
- Body
- PolicyDryRunRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/iam/policies:promoteRequiresiam:policy:publishPromote policies between draft, staging and published
`force` overrides an unsafe dry-run verdict and is annotated on the audit event, because that is the decision somebody will be asked about.
- Body
- PolicyPromotionRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- DELETE
/v1/iam/policies/{name}Requiresiam:policy:deleteDelete a policy from one environment
Parameters (4)
name· path · requiredenvironment· query — draft, staging or published. Defaults to draft.X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- GET
/v1/iam/policies/{name}Requiresiam:policy:readFetch one policy
Carries the compiled Cedar as well as the structured definition, so a decision can be replayed exactly as it was made.
Parameters (3)
name· path · requiredenvironment· query — draft, staging or published. Defaults to draft.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- PUT
/v1/iam/policies/{name}Requiresiam:policy:writeCreate or replace a policy
Saving produces a new version and a digest over the compiled Cedar, which is the unit of “did this change”. Written to the draft environment; promoting it is a separate, dry-runnable step.
- Body
- PolicyDocumentInput
Parameters (3)
name· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- PUT
/v1/iam/policy-testsRequiresiam:policy:writeReplace the policy test suite
Run against an environment before a promotion, which is what turns “we think this change is safe” into an answer.
- Body
- PolicyTestSuite
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/iam/policy-tests:runRequiresiam:policy:simulateRun the policy test suite
Answers 409 when any case fails, so a pipeline step can branch on the status rather than parse the body.
Parameters (3)
environment· query — Which policy set to run against. Defaults to published.X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/iam/simulateRequiresiam:policy:simulateEvaluate a decision without taking the action
The documented alias of `/v1/authorize:simulate`.
- Body
- SimulateRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
project 3
- GET
/v1/projectsRequiresplatform:project:readList projects in the tenant
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/projectsRequiresplatform:project:createCreate a project
What usage is attributed to. A project that charges nowhere makes the showback wrong for every other project in the tenant, which is why the cost centre is not optional in practice.
- Body
- CreateProjectRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- GET
/v1/projects/{name}Requiresplatform:project:readFetch one project
Parameters (2)
name· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
quota 3
- GET
/v1/quotasRequiresplatform:quota:readList quotas with their current consumption
Parameters (2)
scope· query — Only quotas at this scope URN.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- PUT
/v1/quotasRequiresplatform:quota:setSet a quota on one dimension at one scope
A soft limit warns and the hard limit refuses. Both are needed: a quota that only refuses gives an operator no notice, and one that only warns is not a quota.
- Body
- SetQuotaRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/quotas:checkRequiresplatform:quota:readAsk whether an amount would fit under the quota
Consumes nothing. Called before a provision, so the refusal arrives before the side effects.
- Body
- CheckQuotaRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
role 5
- GET
/v1/iam/rolesRequiresiam:role:listList roles, built-in and custom
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/iam/rolesRequiresiam:role:createCreate a role
Every permission must exist in the catalog. A role naming a permission nothing checks is a role that appears to grant something and does not.
- Body
- CreateRoleRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- DELETE
/v1/iam/roles/{name}Requiresiam:role:deleteDelete a role
Refused while anybody still holds it, because the alternative is silently removing their access.
Parameters (3)
name· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- GET
/v1/iam/roles/{name}Requiresiam:role:readFetch one role with its effective permissions
`effective_permissions` is the closure over inheritance, which is the only number that answers what holding this role actually lets somebody do.
Parameters (2)
name· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- PATCH
/v1/iam/roles/{name}Requiresiam:role:updateChange a role
Absent fields are left alone. Supplying `permissions` replaces the list entire.
- Body
- UpdateRoleRequest
Parameters (3)
name· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
share 3
tenant 7
- GET
/v1/tenantsRequiresplatform:tenant:readList tenants
Everybody may ask; what differs is what the question is about. Staff are answered with the register, a customer with themselves — authorizing both against the caller’s own tenant and then returning every row would hand the customer list to anyone holding a permission their own tenant-admin role includes by default.
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/tenantsRequiresplatform:tenant:createRegister a tenant
`isolation` is the commercial decision made technical: a dedicated tenant gets its own schema. The key appears in every URN of theirs and cannot be changed afterwards.
- Body
- CreateTenantRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/tenants:provisionRequiresplatform:tenant:provisionCreate a company that signed up, with its first administrator
Self-service sign-up (A5). Creates the tenant and its default workspace, issues the service grants every customer tenant needs, and gives the first user the built-in `tenant-admin` role in that tenant. Idempotent: a retried sign-up finds the tenant and issues only what is missing. Callable from the platform tenant only — a customer administrator holding wildcard permissions in their own tenant still cannot create another company.
- Body
- ProvisionTenantRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- GET
/v1/tenants/{key}Requiresplatform:tenant:readFetch one tenant
Reading your own record is a same-tenant read; reading somebody else’s is a read of the register, which lives in the platform tenant. So the operator console reaches it with the grant it already holds and a customer is refused by tenant isolation rather than by a check written into the handler.
Parameters (2)
key· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/tenants/{key}/exportRequiresplatform:tenant:exportExport a tenant’s configuration
The portability half of the exit story: what a customer takes with them, in a format they can read without us.
Parameters (2)
key· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/tenants/{key}/lifecycleRequiresplatform:tenant:lifecycleSuspend, terminate or restore a tenant
Suspension stops new spend and keeps the data. Termination starts the clock on deletion, which is a separate, evidenced operation rather than a state change.
- Body
- TenantLifecycleRequest
Parameters (3)
key· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- PUT
/v1/tenants/{key}/residencyRequiresplatform:tenant:updateSet which substrates a tenant’s resources may live on
The residency floor. Enforced at every provision and every query plan, not only at creation — a rule applied once is a rule a migration can break.
- Body
- ResidencyRequest
Parameters (3)
key· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
workspace 9
- DELETE
/v1/membershipsRequiresplatform:workspace:manage_membersRemove a membership
Identified by all three of principal, scope and role, in the query string rather than a body: the same person may hold two roles at one scope, and dropping the wrong one is silent.
Parameters (5)
principal· query · required — Whose membership.scope· query · required — At which scope.role· query · required — Which role.X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- GET
/v1/membershipsRequiresplatform:workspace:readList memberships
Parameters (2)
principal· query — Only memberships held by this principal URN.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/membershipsRequiresplatform:workspace:manage_membersGrant a principal a role at a scope
- Body
- CreateMembershipRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- GET
/v1/workspacesRequiresplatform:workspace:readList workspaces in the tenant
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/workspacesRequiresplatform:workspace:createCreate a workspace
The unit of collaboration and of cost. `cloud_mode` decides whether resources here are ordered from ProjectX or provisioned onto the customer’s own substrate, and on a customer-owned substrate no infrastructure margin is metered.
- Body
- CreateWorkspaceRequest
Parameters (2)
X-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- GET
/v1/workspaces/{name}Requiresplatform:workspace:readFetch one workspace
Parameters (2)
name· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/workspaces/{name}/archiveRequiresplatform:workspace:archiveArchive a workspace
Stops new work in it and keeps everything. Not a delete: the resources and their history remain.
Parameters (3)
name· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- POST
/v1/workspaces/{name}/cloneRequiresplatform:workspace:cloneCopy a workspace’s configuration under a new name
Memberships and resources are not copied: a clone that carried the original’s access list would be a way to hand somebody a second copy of data they were granted once.
- Body
- CloneWorkspaceRequest
Parameters (3)
name· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
- PUT
/v1/workspaces/{name}/residencyRequiresplatform:workspace:updateNarrow a workspace’s substrate allowance
May narrow the tenant’s allowance and never widen it.
- Body
- ResidencyRequest
Parameters (3)
name· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.Idempotency-Key· header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.