ProjectX Operator
Staff-only, cross-tenant: the staff directory, break-glass impersonation, tenant lifecycle, cross-tenant audit search and the operations browser. Published rather than kept internal because a customer is entitled to know what the console we run their platform from can do.
104 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.
agent 6
- GET
/v1/operator/agent-runs/{tenant}/{run}Requiresplatform:agent:readReplay one agent run’s full trace, including authorization decisions
Every step in order — the reasoning, the tool, the PDP decision and the outcome — so what an agent did and whether it was allowed to is read from the record rather than reconstructed.
- Returns
- AgentRunTrace
Parameters (3)
tenant· path · requiredrun· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/agentsRequiresplatform:agent:readThe cross-tenant agent registry with tools, scopes, budgets and blast radius
Every agent on the platform, each with its live kill state folded in. The one place a platform admin sees every tenant’s automation at once — a view no single tenant should have and the operator must.
- Returns
- AgentRegistry
Parameters (2)
tenant· query — One tenant. Omit for every agent.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/kill-switchRequiresplatform:agent:readKill-switch engagements
- Returns
- KillEngagements
Parameters (2)
live· query — Only engagements not yet liftedX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/kill-switchRequiresplatform:agent:killEngage the kill switch at agent, tenant or global scope
Global stops every agent everywhere — the break-glass, and a platform-admin action because stopping every customer’s automation at once is exactly the power that must not rest with one support engineer. Records which runtimes acknowledged; the five-second guarantee is the runtime checking the switch on the hot path of every step.
- Body
- EngageKillSwitchRequest
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/operator/kill-switch/{id}/effectRequiresplatform:agent:readThe live effect of a kill: reached, acknowledged, and any that did not
The count that turns "we pulled the switch" into a claim with evidence. A reached runtime with no acknowledgement past the five-second window is reported as outstanding — not assumed stopped, not assumed fine.
- Returns
- KillEffect
Parameters (2)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/kill-switch/{id}/liftRequiresplatform:agent:killRestore service after a kill — a separate, deliberate act
A kill does not time out and does not lift itself; the failure mode of an auto-lifting switch is the incident resuming the moment everyone looks away. Restoring needs a reason and tells the runtimes to resume.
- Body
- LiftKillSwitchRequest
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.
audit 6
- GET
/v1/operator/auditRequiresplatform:audit:readSearch audit events across tenants
Omit `tenant` to search every chain at once. Doing so is itself audited, and a search naming one tenant is disclosed into that tenant’s chain: staff cannot read a customer’s log without the log recording it.
- Returns
- AuditSearchResult
Parameters (11)
tenant· query — One tenant. Omit to search all of them.principal· query — Exact principal URNresource· query — Exact URN, or a prefix ending in *action· query — Exact permission-catalog actionpillar· query — Actions in one pillardecision· query — allow, deny or errorgrant_id· query — Everything done under one grantfrom· query — ISO-8601 lower bound, inclusiveto· query — ISO-8601 upper bound, inclusivelimit· query — Up to 500X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/audit/exportRequiresplatform:audit:exportExport audit events for an auditor or a SIEM
The same search as `/v1/operator/audit`, rendered as CSV, OCSF or CEF. A single-tenant JSON export carries the chain verdict; a cross-tenant one does not, because each chain verifies separately and one verdict over five chains would be a claim nobody can check.
Parameters (12)
tenant· query — One tenant. Omit to export across all of them.format· query — `json`, `csv`, `ocsf` or `cef`. Defaults to json.principal· query — Exact principal URNresource· query — Exact URN, or a prefix ending in *action· query — Exact permission-catalog actionpillar· query — Actions in one pillardecision· query — allow, deny or errorgrant_id· query — Everything done under one grantfrom· query — ISO-8601 lower bound, inclusiveto· query — ISO-8601 upper bound, inclusivelimit· query — Up to 500X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/audit/operator-actionsRequiresplatform:audit:readWhat staff did to customers, to whom, when, and approved by whom
Cross-checks the platform chain against the customer chains, and each action against the grant or bulk action it was exercised under. `undisclosed` and `unapproved` are lists rather than counts, because a gap in either control is something to investigate rather than to trend. Disclosure is counted per customer, so one bulk action owes as many disclosures as it reached tenants.
Parameters (3)
from· query — ISO-8601 lower boundto· query — ISO-8601 upper boundX-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/audit/tenantsRequiresplatform:audit:readTenants that have written at least one audit event
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/audit/verifyRequiresplatform:audit:verifyVerify a hash chain
One tenant, or every tenant when `tenant` is omitted. Verification is always per chain — a mixed result set has no chain to verify, and a green tick over a meaningless check is worse than none.
- Body
- ChainVerifyRequest
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/operator/compliance/reports/{kind}Requiresplatform:audit:readOne compliance report over a customer’s window
`kind` is `access_review`, `privileged_action` or `data_access`. The three that make up an evidence pack, available singly for the reviewer who wants one of them.
Parameters (5)
kind· path · requiredtenant· query · required — Whose chain. Required.from· query · required — Inclusive RFC 3339 lower bound. Required.to· query · required — Exclusive RFC 3339 upper bound. Required.X-Request-Id· header — Echoed on the response and recorded on the audit event.
canary 1
- GET
/v1/operator/canariesRequiresplatform:canary:readThe five canaries with current state, history and last failure
The current pillar health (a red canary declares its pillar degraded regardless of any other dashboard), the recent run history, and the last failure per canary.
- Returns
- CanaryReport
Parameters (3)
canary· query — One canary: login, query, camera, provision or agentlimit· query — How much history, default 50X-Request-Id· header — Echoed on the response and recorded on the audit event.
compliance 3
- GET
/v1/operator/compliance/article-30Requiresplatform:compliance:readA customer’s Article 30 record of processing activities
Generated live from the catalog rather than stored, so it cannot drift from what is actually being processed. The customer’s chain records that we produced it.
Parameters (2)
tenant· query · required — Whose record. Required.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/compliance/dpia/{urn}Requiresplatform:compliance:readThe DPIA support pack for one of a customer’s resources
What is processed, where, why, for how long, and who has actually touched it — kept apart from who *could*, because the gap between the two is the finding.
Parameters (3)
urn· path · required — The resource URN, used verbatim.window_days· query — How far back to read access. Defaults to 90.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/compliance/evidence-packsRequiresplatform:compliance:generateSeal an evidence pack for a customer’s audit window
Bundles chain verification, the three compliance reports, the Article 30 record and the legal holds in force, sealed with a digest the recipient can check. The digest is recorded in the customer’s chain, so which pack left is evidence and not just that one did.
- Body
- TenantEvidenceWindow
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.
customer_user 4
- GET
/v1/operator/customer-usersRequiresplatform:customer_user:readSearch every company’s users by name or email
At least three characters. Disclosed to each company that returned a match. Companies whose directory could not be read are listed, so an empty answer is never mistaken for a complete one.
Parameters (2)
search· query · required — Username, name or email fragment.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/tenants/{key}/usersRequiresplatform:customer_user:readOne company’s users, as metadata
Parameters (6)
key· path · requiredsearch· query — Username, name or email fragment.state· query — pending, active, suspended or deprovisioned.cursor· query — Opaque cursor from the previous page.limit· query — Page size, at most 200.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/tenants/{key}/users/{username}Requiresplatform:customer_user:readOne customer user, with the kinds of factor they have enrolled
Parameters (3)
key· path · requiredusername· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/tenants/{key}/users/{username}/actionsRequiresplatform:customer_user:manageSuspend, reactivate or sign out a customer user, or require a new passkey
The reason is required and lands in the customer’s own audit chain and in the notification they are sent. Read-only staff are refused.
- Body
- CustomerUserActionRequest
Parameters (4)
key· path · requiredusername· 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.
deployment 3
- GET
/v1/operator/platform/fleetRequiresplatform:deployment:readWhat every service is running, and whether it is ready to serve
Asks each service’s readiness endpoint live rather than reading a cached inventory: the reason to open this page is a suspicion that what is running is not what you think, and a cache is the same suspicion one layer down. A service that does not answer is reported as unreachable rather than dropped from the list.
- Returns
- FleetReport
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/platform/schedulesRequiresplatform:deployment:readEvery scheduled job across every tenant, worst first
Ordered by whether somebody needs to look: jobs whose last run would not start, then jobs past due with nothing having started them. Both are invisible from a list of operations, which in this failure simply has fewer rows in it than it should.
- Returns
- ScheduleBoard
Parameters (2)
tenant· query — Restrict to one customer’s schedulesX-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/statusRequiresplatform:deployment:readEach pillar’s health, from the canaries and nothing else
The Status_Page. It reads only the canaries’ last recorded results and the clock, so it keeps answering when the observability stack that would otherwise report health is itself the broken thing. A pillar is degraded when its canary last failed, or when the canary has not reported for two intervals — the second is called out as `absent` rather than `failed`, because a silent canary is not knowledge of a failure, it is the absence of knowledge.
- Returns
- CanaryStatusPage
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
face_recognition 5
- GET
/v1/operator/face-recognitionRequiresplatform:face_recognition:readThe regulator-ready view of every face-recognition enablement
Every tenant with the module, its lawful-basis declaration, its named accountable owner and its state — the document a regulator asks for first.
- Returns
- FaceRecognitionRegulatorView
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- DELETE
/v1/operator/tenants/{key}/face-recognitionRequiresplatform:face_recognition:disableDisable face recognition and purge the biometric data
Destroys the watchlists and face templates and issues a sealed certificate saying so, which the customer can hand to their own regulator. Refused if no purger is configured — disabling blind would leave the biometric data on disk.
- Body
- DisableFaceRecognitionRequest
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.
- GET
/v1/operator/tenants/{key}/face-recognitionRequiresplatform:face_recognition:readOne tenant’s face-recognition enablement record
Parameters (2)
key· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/tenants/{key}/face-recognitionRequiresplatform:face_recognition:requestRequest face recognition for a tenant
Refused unless all three declarations are present — a signed contract addendum, a structured lawful basis with its detail and retention, and a named verified accountable owner. Two of the three is not nearly there; it is a refusal that names what is missing. Produces a pending request; two approvals from two different jobs are still needed.
- Body
- RequestFaceRecognitionRequest
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.
- POST
/v1/operator/tenants/{key}/face-recognition/approvalsRequiresplatform:face_recognition:approveApprove a pending face-recognition request
Two seats must both approve — a compliance operator and a platform admin — and the approver must actually hold the role. When both seats are in, the tenant is notified and face-match auditing is locked on and cannot be turned off.
- Body
- ApproveFaceRecognitionRequest
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.
feature_flag 2
- GET
/v1/operator/feature-flagsRequiresplatform:feature_flag:readFeature flags at every scope
Parameters (4)
key· query — One flag keyscope· query — global, plan or tenanttarget· query — The plan or tenant a scoped flag applies toX-Request-Id· header — Echoed on the response and recorded on the audit event.
- PUT
/v1/operator/feature-flagsRequiresplatform:feature_flag:setSet a feature flag at a scope, with a reason on the flip
Global, plan or tenant scope, most specific wins. Every flip carries a reason and lands in the audit trail — a flag flipped without a why is a change nobody can account for. A tenant-scoped flip is disclosed into that tenant’s chain.
- Body
- SetFeatureFlagRequest
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.
impersonation 9
- GET
/v1/operator/bannerRequiresplatform:impersonation:readLive impersonation state for the caller
Every live grant, not one. An operator holding two at once is exactly when a single-grant banner understates how much access is open.
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/impersonationsRequiresplatform:impersonation:readImpersonation grants, filtered
Parameters (4)
state· query — pending, active, ended, expired or rejectedtenant· query — Only grants against this tenantrequested_by· query — Only grants asked for by this operatorX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/impersonationsRequiresplatform:impersonation:requestAsk to enter a customer tenant
Creates a pending request. Two distinct approvers are required before it activates, and the customer is notified at request time rather than at activation — a refused request is information they are entitled to as well.
- Body
- ImpersonationRequest
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/operator/impersonations/{id}Requiresplatform:impersonation:endEnd a session and disclose it
Returns the summary sent to the customer: scope, approvals, duration, and every resource touched. Sent whether the session read anything or not.
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/operator/impersonations/{id}Requiresplatform:impersonation:readOne impersonation grant, including every disclosed read
Parameters (2)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/impersonations/{id}/approvalsRequiresplatform:impersonation:approveApprove a break-glass request
The requester cannot approve their own. When the target tenant operates its own substrate, one approval must carry `on_behalf_of_customer`.
- Body
- ImpersonationApproval
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/operator/impersonations/{id}/readsRequiresplatform:impersonation:useCheck and record one read under a grant
Permission and disclosure in a single call. Splitting them would leave a second call somebody can forget, and the read log is what the customer’s end-of-session disclosure is built from.
- Body
- DisclosedRead
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/operator/impersonations/{id}/rejectionRequiresplatform:impersonation:approveRefuse a break-glass request
- Body
- ImpersonationRejection
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/operator/impersonations/pendingRequiresplatform:impersonation:readThe approval queue, with what each request is still waiting for
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
incident 9
- GET
/v1/operator/incidentsRequiresplatform:incident:readIncidents, newest first
- Returns
- IncidentList
Parameters (3)
state· query — declared, mitigated, resolved or closedseverity· query — sev1 to sev4X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/incidentsRequiresplatform:incident:declareDeclare an incident with severity, commander and impact scope
An incident names one accountable commander — not a channel — and its impact by tenant, region and pillar. It opens with a timeline that every subsequent action appends to.
- Body
- DeclareIncidentRequest
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/operator/incidents/{id}Requiresplatform:incident:readOne incident with its full timeline
Parameters (2)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/incidents/{id}/impactRequiresplatform:incident:updateSet the customer impact scope by tenant, region and pillar
- Body
- IncidentImpactRequest
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/operator/incidents/{id}/reviewRequiresplatform:incident:updateFile the post-incident review — a required artifact
What happened, why, what was done, and at least one change that will stop it recurring. Filing it is what lets the incident be closed.
- Body
- PostIncidentReviewRequest
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/operator/incidents/{id}/statusRequiresplatform:incident:publishPublish a status-page update from inside the incident
The update is recorded on the incident, so the public page and the incident record cannot tell two different stories — the page is a projection of what the incident said.
- Body
- PublishStatusRequest
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/operator/incidents/{id}/timelineRequiresplatform:incident:updateAdd a correlated entry to the incident timeline
- Body
- IncidentTimelineRequest
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/operator/incidents/{id}/transitionRequiresplatform:incident:updateMove an incident along its lifecycle
declared, mitigated, resolved, closed. An incident cannot be closed until its post-incident review is filed.
- Body
- IncidentTransitionRequest
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/operator/status-pageRequiresplatform:incident:readThe status page: pillar health plus the current word on each open incident
Pillar health comes from the canaries — a red canary declares its pillar degraded in one place — and each open incident shows its latest published update. This is the projection the public status page renders; the operator reads the same assembled view.
- Returns
- StatusPage
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
knowledge 5
- GET
/v1/operator/knowledge/articlesRequiresplatform:knowledge:readKnowledge base articles
Each carries whether it is overdue for review, computed from the clock rather than stamped by a job, so an article that went stale while nobody was running the reminder reads as stale the moment it is opened.
Parameters (3)
tag· query — One tagpublic· query — true for the ones a customer may be linked toX-Request-Id· header — Echoed on the response and recorded on the audit event.
- PUT
/v1/operator/knowledge/articles/{slug}Requiresplatform:knowledge:writeWrite or replace an article
An article is internal unless it says otherwise. A runbook that reads "restart the shard and blame the CDN" is not a document to hand somebody, and the way that gets sent by accident is a knowledge base with no such distinction.
- Body
- ArticleRequest
Parameters (3)
slug· 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/operator/knowledge/responsesRequiresplatform:knowledge:readCanned responses, with how well each has actually worked
Each carries its send count and how many of those tickets were escalated afterwards. A template sent four hundred times that precedes an escalation three times in four is not a time-saver, it is a way to fail faster, and nobody finds that out from a folder of files.
Parameters (2)
tag· query — One tagX-Request-Id· header — Echoed on the response and recorded on the audit event.
- PUT
/v1/operator/knowledge/responses/{slug}Requiresplatform:knowledge:writeWrite or replace a canned response
The body may use {{tenant}}, {{reference}}, {{subject}} and {{assignee}}. The send and escalation counts survive an edit, so a template cannot escape its own record by having a typo fixed.
- Body
- CannedResponseRequest
Parameters (3)
slug· 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/operator/tickets/{tenant}/{reference}/suggestionsRequiresplatform:knowledge:readArticles and canned responses that might help
Matched on tag overlap, deliberately. A relevance model that is usually right teaches an engineer to stop reading the suggestions, and the day it is wrong is the day one gets sent to a customer unread.
Parameters (3)
tenant· path · requiredreference· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
license 3
- GET
/v1/operator/licensesRequiresplatform:license:readLicence grants, optionally for one tenant
Parameters (2)
tenant· query — One tenant. Omit for every licence.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/tenants/{key}/licensesRequiresplatform:license:grantGrant a module licence to a tenant
A licence names the contract it is sold under and, optionally, a term. Licensing a module is not the same as enabling it — face recognition is licensed here and enabled through the gate.
- Body
- GrantLicenseRequest
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.
- DELETE
/v1/operator/tenants/{key}/licenses/{module}Requiresplatform:license:revokeRevoke a tenant’s module licence
- Body
- RevokeLicenseRequest
Parameters (4)
key· path · requiredmodule· 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.
operation 6
- GET
/v1/operator/operationsRequiresplatform:operation:readLong-running operations across tenants
Parameters (5)
tenant· query — One tenant. Omit to browse all of them.kind· query — Workflow kindstate· query — pending, running, succeeded, failed or cancelledlimit· query — Up to 200X-Request-Id· header — Echoed on the response and recorded on the audit event.
- DELETE
/v1/operator/operations/{tenant}/{id}Requiresplatform:operation:cancelCancel a running operation
Cancellation runs the workflow’s compensations. A reason is required because the customer sees this in their own chain.
- Body
- OperationCancelRequest
Parameters (4)
tenant· path · requiredid· 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/operator/operations/{tenant}/{id}Requiresplatform:operation:readOne operation, with every step and its retries
Parameters (3)
tenant· path · requiredid· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/operations/{tenant}/{id}/retryRequiresplatform:operation:retryRun a customer’s failed operation again from where it stopped
Continues rather than restarts: only the failed and rolled-back steps run again, and the engine decides which idempotency keys carry over. A reason is required because the customer reads this in their own chain, where “a staff member re-ran work on your account” without a why is the sentence that generates the next ticket.
- Body
- OperationRetryRequest
Parameters (4)
tenant· path · requiredid· 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/operator/operations/{tenant}/{id}/signalRequiresplatform:operation:signalSend a named signal to a customer’s running operation
Read by steps that look for it, at the next step boundary or by a step that polls. It does not interrupt work already in flight, and a signal nothing picks up stays visible as unread rather than being reported as delivered.
- Body
- OperationSignalRequest
Parameters (4)
tenant· path · requiredid· 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/operator/platform/schedules/{tenant}/{name}/enabledRequiresplatform:operation:schedulePause or resume a customer’s scheduled job
Stops the job firing without editing it, so an operator halting a misbehaving nightly export at 3am does not have to retype its cron expression correctly first. Resuming does not backfill the runs missed while it was off.
- Body
- ScheduleEnabledRequest
Parameters (4)
tenant· path · requiredname· 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.
search 2
- GET
/v1/operator/searchRequiresplatform:search:readSearch tenants, staff, substrates and URNs — metadata only
Never returns payload. A hit carries enough to recognize a thing and navigate to it; the contents are behind the drawer’s payload tabs, which prompt for break-glass. A search box returning the same text without a grant, a reason and an entry in the customer’s chain would be a way around break-glass with autocomplete. Sources that would not answer are named, because “nothing matched” and “nothing matched anywhere we could look” are different answers.
- Returns
- SearchResults
Parameters (4)
q· query — At least two characterskind· query — tenant, staff, substrate or resourcelimit· query — Up to 50X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/search/sourcesRequiresplatform:search:readWhich sources this deployment can search
The console shows these in the empty state, so an operator knows what the box covers before they conclude a thing does not exist.
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
slo 3
- GET
/v1/operator/slosRequiresplatform:slo:readThe SLO dashboard with error budgets and burn rate
Every objective, platform-wide and per tenant, with the error budget it implies and how much of it the observed failure has spent. A burn rate above 1 means the budget will be gone before the window closes.
- Returns
- SloDashboard
Parameters (2)
tenant· query — One tenant. Omit for platform-wide plus all.X-Request-Id· header — Echoed on the response and recorded on the audit event.
- PUT
/v1/operator/slosRequiresplatform:slo:setDefine or update an SLO
The objective is a fraction (0.999 for three nines) over a rolling window; the error budget is one minus the objective. A per-tenant SLO names the tenant.
- Body
- SetSloRequest
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/operator/slos:catalogRequiresplatform:slo:readThe seven platform SLOs of the system definition with their alert state
Each SLO with its target and its alert rule — burn rate for the availability objectives, a sustained-latency threshold for the p95/p99 and freshness ones. An SLO with no live measurement reports pending rather than a fabricated ok: the real figure needs sustained load in a deployed environment, and claiming health without it is the false green this exists to prevent.
- Returns
- PlatformSloCatalog
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
staff 13
- GET
/v1/operator/staffRequiresplatform:staff:readThe ProjectX staff directory
Parameters (3)
role· query — Only staff holding this rolestate· query — active, suspended or offboardedX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/staffRequiresplatform:staff:createOnboard a staff principal
Refused when the requested roles violate separation of duties. The refusal names the control, not just the pair, so the person asking can decide whether to split the work or challenge the rule.
- Body
- StaffOnboardRequest
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/operator/staff-reviewsRequiresplatform:staff:readEvery staff access review campaign
Newest first. A campaign is the certification record of one review round: who held what when it opened, what the reviewer decided, and what closing it revoked.
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/staff-reviewsRequiresplatform:staff:reviewOpen a staff access review campaign
Snapshots every role active staff hold right now. The named reviewer decides each item; anything left undecided at close is revoked, because an access review whose silence keeps access is not a review.
- Body
- StaffReviewLaunch
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/operator/staff-reviews/{id}Requiresplatform:staff:readOne staff access review campaign
Parameters (2)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/staff-reviews/{id}/closeRequiresplatform:staff:reviewClose a campaign and strip every revoked role
The write-back is the point of the exercise: closing removes each revoked role from the directory in the same step, with the campaign URN as the recorded reason. Undecided items close as revocations.
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/operator/staff-reviews/{id}/decisionsRequiresplatform:staff:reviewDecide one item of a campaign
Only the named reviewer may decide, and never their own roles. A closed campaign refuses further decisions — the certification is final once issued.
- Body
- StaffReviewDecision
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/operator/staff-reviews/{id}/evidenceRequiresplatform:staff:readThe certification record an auditor is handed
One flat list: every role held at launch, who decided it, what they decided, and the counts. This is the artifact SOC 2 asks an access review for.
Parameters (2)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/staff-sodRequiresplatform:staff:readSeparation-of-duties violations across the directory
Reports what exists now rather than only refusing what is new, so a conflict pair added to the rules after the fact is still found.
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- DELETE
/v1/operator/staff/{username}Requiresplatform:staff:offboardOffboard a staff principal
Keeps the URN resolvable. It is the principal on audit events that outlive the employment, and a log that reads "unknown principal" is not a log.
- Body
- StaffOffboardRequest
Parameters (3)
username· 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/operator/staff/{username}Requiresplatform:staff:readOne staff principal
Parameters (2)
username· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- PUT
/v1/operator/staff/{username}/read-onlyRequiresplatform:staff:updatePut a staff member in read-only mode, or take them out of it
New accounts start read-only. Lifting it is a separate decision from granting roles, so an over-generous onboarding form cannot by itself let anybody do anything.
- Body
- StaffReadOnlyRequest
Parameters (3)
username· 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/operator/staff/{username}/rolesRequiresplatform:staff:updateReplace a staff member’s roles
The whole set at once. Separation of duties is a property of the set, and an incremental add would make the check depend on request ordering.
- Body
- StaffRolesRequest
Parameters (3)
username· 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.
tenant 16
- GET
/v1/operator/bulk-actionsRequiresplatform:tenant:readBulk actions requested, approved, executed or rejected
Parameters (4)
state· query — pending, approved, executed, rejected, expired, failedkind· query — One of the bulk action kindsrequested_by· query — Staff principal URNX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/bulk-actionsRequiresplatform:tenant:lifecycleRequest a bulk action
Parks for a second approver whenever dual control applies, which is anything destructive and anything at or above the configured tenant threshold. Rate-limited by tenants touched rather than by requests made.
- Body
- BulkActionRequest
- Returns
- BulkAction
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/operator/bulk-actions/{id}Requiresplatform:tenant:readOne bulk action, its plan and its approvals
Parameters (2)
id· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/bulk-actions/{id}/approvalsRequiresplatform:tenant:lifecycleApprove a bulk action
The requester cannot approve their own, and nobody may approve twice.
- Body
- BulkActionApproval
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/operator/bulk-actions/{id}/executionRequiresplatform:tenant:lifecycleExecute an approved bulk action
Recounts first and refuses if the fleet has changed shape since approval — an approval is consent to a described outcome, not to the query that produced it. Reports a per-tenant result; partial failure is reported as failed.
- Returns
- BulkAction
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/operator/bulk-actions/{id}/rejectionRequiresplatform:tenant:lifecycleReject a pending bulk action
- Body
- BulkActionRejection
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/operator/bulk-actions/kindsRequiresplatform:tenant:readWhat may be done in bulk
A closed list. Deletion is absent on purpose: it has no undo, it already has a per-tenant path with a census and a certificate, and a bulk form of it would be one request that destroys a business.
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/bulk-actions/previewRequiresplatform:tenant:readWhat a bulk action would do, without doing any of it
Counts per tenant, names the ones that would change nothing, and reports any tenant that would not answer. An unreadable tenant makes the plan incomplete, and an incomplete plan cannot be requested.
- Body
- BulkActionPreviewRequest
- Returns
- BulkActionPlan
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/operator/productsRequiresplatform:tenant:readLifecycle, Verify and Workplace operations across customers
Allow-listed counts, states, usage and provider health. Unreadable customers are explicit gaps; no customer content or verification payloads are returned.
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/tenantsRequiresplatform:tenant:readEvery tenant, with live impersonations and audit volume
- Returns
- TenantList
Parameters (1)
X-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/tenantsRequiresplatform:tenant:createCreate a tenant
Isolation is required rather than defaulted. Changing it afterwards means moving the tenant’s data, so the choice is only cheap at this moment and should be visibly made.
- Body
- TenantCreateRequest
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/operator/tenants/{key}Requiresplatform:tenant:deleteDelete a terminating tenant and issue the certificate
Recomputes the blast radius rather than trusting the one the operator saw, refuses while any legal hold stands, and seals a certificate whose digest the customer can recompute.
- Body
- TenantDeleteRequest
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.
- GET
/v1/operator/tenants/{key}Requiresplatform:tenant:readOne tenant
Parameters (2)
key· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/tenants/{key}/blast-radiusRequiresplatform:tenant:readWhat deleting this tenant would destroy
Counts by pillar and kind, legal holds that block the deletion, and the substrates ProjectX does not operate and therefore cannot wipe.
- Returns
- DeletionBlastRadius
Parameters (2)
key· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- GET
/v1/operator/tenants/{key}/exportRequiresplatform:tenant:exportThe tenant’s configuration, for support or migration
Parameters (2)
key· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/tenants/{key}/lifecycleRequiresplatform:tenant:lifecycleSuspend, resume or terminate a tenant
The reason is mandatory and lands in the customer’s own audit chain. Suspending an account without saying why is how a support escalation becomes a dispute nobody can reconstruct.
- 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.
ticket 8
- GET
/v1/operator/ticketsRequiresplatform:ticket:readThe support queue, ordered by what is closest to breaching
Sorted by time to breach rather than by age, and a ticket whose clock is stopped waiting on the customer sinks below every ticket whose clock is running. Sorting by age puts the tickets we are not currently failing at the top, which is how a desk stays busy and still misses its targets.
Parameters (7)
tenant· query — One customer. Omit for the whole queue.state· query — open, pending_customer, pending_internal, resolved, closedpriority· query — urgent, high, normal or lowassignee· query — Staff URNunassigned· query — true for the tickets nobody ownstag· query — One tagX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/ticketsRequiresplatform:ticket:createRaise a ticket on a customer’s behalf
For the call that came in by phone. The customer is recorded as having raised it, because a ticket attributed to the engineer who typed it is a ticket the customer cannot find.
- Body
- TicketRequest
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/operator/tickets/{tenant}/{reference}Requiresplatform:ticket:readOne ticket, its whole thread and where it stands against the SLA
Parameters (3)
tenant· path · requiredreference· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- PUT
/v1/operator/tickets/{tenant}/{reference}/assigneeRequiresplatform:ticket:updateAssign a ticket, or hand it back to the queue
An empty assignee unassigns. The staff member is checked, because a ticket assigned to a typo has an owner in the grid and nobody in the world.
- Body
- TicketAssigneeRequest
Parameters (4)
tenant· path · requiredreference· 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/operator/tickets/{tenant}/{reference}/contextRequiresplatform:ticket:readWhat has been happening to this customer, without their data
Their state, what ProjectX staff did to them lately, what the platform refused them, and what is running. Every field is metadata: the support desk is the most plausible route to a customer’s payload, because the person asking has a sympathetic reason and the person deciding is trying to help. What the platform cannot yet see — plan, spend — is named as a gap rather than shown as a zero.
Parameters (3)
tenant· path · requiredreference· path · requiredX-Request-Id· header — Echoed on the response and recorded on the audit event.
- POST
/v1/operator/tickets/{tenant}/{reference}/escalationsRequiresplatform:ticket:escalateEscalate to another staff member, with a reason
Appended rather than set. "Escalated twice and nobody picked it up" is the sentence a review needs, and a boolean cannot say it. The canned response last sent is charged against its own record at the same time, which is how a template that does not answer the question gets found.
- Body
- TicketEscalationRequest
Parameters (4)
tenant· path · requiredreference· 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/operator/tickets/{tenant}/{reference}/messagesRequiresplatform:ticket:updateReply, or add an internal note
A reply may name a canned response instead of a body, in which case the template is filled from the ticket and refused rather than sent if a placeholder has nothing behind it. An internal note does not start the response clock, because it is not a response.
- Body
- TicketMessageRequest
Parameters (4)
tenant· path · requiredreference· 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/operator/tickets/{tenant}/{reference}/stateRequiresplatform:ticket:updateMove a ticket through its states
Entering pending_customer stops the SLA clock and leaving it banks the time waited, so a desk is never measured on how fast its customers reply. Closed is final; resolved is not, because a customer replying to a resolved ticket reopens it.
- Body
- TicketStateRequest
Parameters (4)
tenant· path · requiredreference· 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.