Skip to content
← All services

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}Requires platform:agent:read

    Replay 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 · required
    • run · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operator/agentsRequires platform:agent:read

    The 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-switchRequires platform:agent:read

    Kill-switch engagements

    Returns
    KillEngagements
    Parameters (2)
    • live · query — Only engagements not yet lifted
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/kill-switchRequires platform:agent:kill

    Engage 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}/effectRequires platform:agent:read

    The 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 · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/kill-switch/{id}/liftRequires platform:agent:kill

    Restore 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 · required
    • 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.

audit 6

  • GET/v1/operator/auditRequires platform:audit:read

    Search 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 URN
    • resource · query — Exact URN, or a prefix ending in *
    • action · query — Exact permission-catalog action
    • pillar · query — Actions in one pillar
    • decision · query — allow, deny or error
    • grant_id · query — Everything done under one grant
    • from · query — ISO-8601 lower bound, inclusive
    • to · query — ISO-8601 upper bound, inclusive
    • limit · query — Up to 500
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operator/audit/exportRequires platform:audit:export

    Export 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 URN
    • resource · query — Exact URN, or a prefix ending in *
    • action · query — Exact permission-catalog action
    • pillar · query — Actions in one pillar
    • decision · query — allow, deny or error
    • grant_id · query — Everything done under one grant
    • from · query — ISO-8601 lower bound, inclusive
    • to · query — ISO-8601 upper bound, inclusive
    • limit · query — Up to 500
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operator/audit/operator-actionsRequires platform:audit:read

    What 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 bound
    • to · query — ISO-8601 upper bound
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operator/audit/tenantsRequires platform:audit:read

    Tenants 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/verifyRequires platform:audit:verify

    Verify 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}Requires platform:audit:read

    One 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 · required
    • tenant · 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/canariesRequires platform:canary:read

    The 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 agent
    • limit · query — How much history, default 50
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

compliance 3

  • GET/v1/operator/compliance/article-30Requires platform:compliance:read

    A 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}Requires platform:compliance:read

    The 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-packsRequires platform:compliance:generate

    Seal 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-usersRequires platform:customer_user:read

    Search 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}/usersRequires platform:customer_user:read

    One company’s users, as metadata

    Parameters (6)
    • key · path · required
    • search · 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}Requires platform:customer_user:read

    One customer user, with the kinds of factor they have enrolled

    Parameters (3)
    • key · path · required
    • username · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/tenants/{key}/users/{username}/actionsRequires platform:customer_user:manage

    Suspend, 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 · required
    • username · path · required
    • 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.

deployment 3

  • GET/v1/operator/platform/fleetRequires platform:deployment:read

    What 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/schedulesRequires platform:deployment:read

    Every 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 schedules
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operator/statusRequires platform:deployment:read

    Each 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-recognitionRequires platform:face_recognition:read

    The 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-recognitionRequires platform:face_recognition:disable

    Disable 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 · required
    • 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/tenants/{key}/face-recognitionRequires platform:face_recognition:read

    One tenant’s face-recognition enablement record

    Parameters (2)
    • key · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/tenants/{key}/face-recognitionRequires platform:face_recognition:request

    Request 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 · required
    • 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/operator/tenants/{key}/face-recognition/approvalsRequires platform:face_recognition:approve

    Approve 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 · required
    • 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.

feature_flag 2

  • GET/v1/operator/feature-flagsRequires platform:feature_flag:read

    Feature flags at every scope

    Parameters (4)
    • key · query — One flag key
    • scope · query — global, plan or tenant
    • target · query — The plan or tenant a scoped flag applies to
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/operator/feature-flagsRequires platform:feature_flag:set

    Set 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/bannerRequires platform:impersonation:read

    Live 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/impersonationsRequires platform:impersonation:read

    Impersonation grants, filtered

    Parameters (4)
    • state · query — pending, active, ended, expired or rejected
    • tenant · query — Only grants against this tenant
    • requested_by · query — Only grants asked for by this operator
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/impersonationsRequires platform:impersonation:request

    Ask 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}Requires platform:impersonation:end

    End 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 · required
    • 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/impersonations/{id}Requires platform:impersonation:read

    One impersonation grant, including every disclosed read

    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/impersonations/{id}/approvalsRequires platform:impersonation:approve

    Approve 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 · required
    • 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/operator/impersonations/{id}/readsRequires platform:impersonation:use

    Check 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 · required
    • 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/operator/impersonations/{id}/rejectionRequires platform:impersonation:approve

    Refuse a break-glass request

    Body
    ImpersonationRejection
    Parameters (3)
    • id · path · required
    • 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/impersonations/pendingRequires platform:impersonation:read

    The 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/incidentsRequires platform:incident:read

    Incidents, newest first

    Returns
    IncidentList
    Parameters (3)
    • state · query — declared, mitigated, resolved or closed
    • severity · query — sev1 to sev4
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/incidentsRequires platform:incident:declare

    Declare 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}Requires platform:incident:read

    One incident with its full timeline

    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/incidents/{id}/impactRequires platform:incident:update

    Set the customer impact scope by tenant, region and pillar

    Body
    IncidentImpactRequest
    Parameters (3)
    • id · path · required
    • 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/operator/incidents/{id}/reviewRequires platform:incident:update

    File 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 · required
    • 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/operator/incidents/{id}/statusRequires platform:incident:publish

    Publish 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 · required
    • 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/operator/incidents/{id}/timelineRequires platform:incident:update

    Add a correlated entry to the incident timeline

    Body
    IncidentTimelineRequest
    Parameters (3)
    • id · path · required
    • 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/operator/incidents/{id}/transitionRequires platform:incident:update

    Move 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 · required
    • 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/status-pageRequires platform:incident:read

    The 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/articlesRequires platform:knowledge:read

    Knowledge 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 tag
    • public · query — true for the ones a customer may be linked to
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/operator/knowledge/articles/{slug}Requires platform:knowledge:write

    Write 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 · required
    • 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/knowledge/responsesRequires platform:knowledge:read

    Canned 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 tag
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/operator/knowledge/responses/{slug}Requires platform:knowledge:write

    Write 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 · required
    • 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}/suggestionsRequires platform:knowledge:read

    Articles 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 · required
    • reference · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

license 3

  • GET/v1/operator/licensesRequires platform:license:read

    Licence 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}/licensesRequires platform:license:grant

    Grant 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 · required
    • 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}/licenses/{module}Requires platform:license:revoke

    Revoke a tenant’s module licence

    Body
    RevokeLicenseRequest
    Parameters (4)
    • key · path · required
    • module · path · required
    • 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.

operation 6

  • GET/v1/operator/operationsRequires platform:operation:read

    Long-running operations across tenants

    Parameters (5)
    • tenant · query — One tenant. Omit to browse all of them.
    • kind · query — Workflow kind
    • state · query — pending, running, succeeded, failed or cancelled
    • limit · query — Up to 200
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/operator/operations/{tenant}/{id}Requires platform:operation:cancel

    Cancel 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 · required
    • id · path · required
    • 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/operations/{tenant}/{id}Requires platform:operation:read

    One operation, with every step and its retries

    Parameters (3)
    • tenant · path · required
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/operations/{tenant}/{id}/retryRequires platform:operation:retry

    Run 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 · required
    • id · path · required
    • 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/operator/operations/{tenant}/{id}/signalRequires platform:operation:signal

    Send 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 · required
    • id · path · required
    • 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.
  • PUT/v1/operator/platform/schedules/{tenant}/{name}/enabledRequires platform:operation:schedule

    Pause 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 · required
    • name · path · required
    • 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.

search 2

  • GET/v1/operator/searchRequires platform:search:read

    Search 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 characters
    • kind · query — tenant, staff, substrate or resource
    • limit · query — Up to 50
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operator/search/sourcesRequires platform:search:read

    Which 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/slosRequires platform:slo:read

    The 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/slosRequires platform:slo:set

    Define 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:catalogRequires platform:slo:read

    The 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/staffRequires platform:staff:read

    The ProjectX staff directory

    Parameters (3)
    • role · query — Only staff holding this role
    • state · query — active, suspended or offboarded
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/staffRequires platform:staff:create

    Onboard 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-reviewsRequires platform:staff:read

    Every 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-reviewsRequires platform:staff:review

    Open 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}Requires platform:staff:read

    One staff access review campaign

    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/staff-reviews/{id}/closeRequires platform:staff:review

    Close 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 · required
    • 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/operator/staff-reviews/{id}/decisionsRequires platform:staff:review

    Decide 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 · required
    • 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}/evidenceRequires platform:staff:read

    The 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 · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operator/staff-sodRequires platform:staff:read

    Separation-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}Requires platform:staff:offboard

    Offboard 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 · required
    • 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/{username}Requires platform:staff:read

    One staff principal

    Parameters (2)
    • username · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/operator/staff/{username}/read-onlyRequires platform:staff:update

    Put 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 · required
    • 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.
  • PUT/v1/operator/staff/{username}/rolesRequires platform:staff:update

    Replace 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 · required
    • 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.

tenant 16

  • GET/v1/operator/bulk-actionsRequires platform:tenant:read

    Bulk actions requested, approved, executed or rejected

    Parameters (4)
    • state · query — pending, approved, executed, rejected, expired, failed
    • kind · query — One of the bulk action kinds
    • requested_by · query — Staff principal URN
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/bulk-actionsRequires platform:tenant:lifecycle

    Request 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}Requires platform:tenant:read

    One bulk action, its plan and its approvals

    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/bulk-actions/{id}/approvalsRequires platform:tenant:lifecycle

    Approve a bulk action

    The requester cannot approve their own, and nobody may approve twice.

    Body
    BulkActionApproval
    Parameters (3)
    • id · path · required
    • 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/operator/bulk-actions/{id}/executionRequires platform:tenant:lifecycle

    Execute 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 · required
    • 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/operator/bulk-actions/{id}/rejectionRequires platform:tenant:lifecycle

    Reject a pending bulk action

    Body
    BulkActionRejection
    Parameters (3)
    • id · path · required
    • 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/kindsRequires platform:tenant:read

    What 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/previewRequires platform:tenant:read

    What 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/productsRequires platform:tenant:read

    Lifecycle, 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/tenantsRequires platform:tenant:read

    Every 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/tenantsRequires platform:tenant:create

    Create 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}Requires platform:tenant:delete

    Delete 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 · required
    • 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/tenants/{key}Requires platform:tenant:read

    One tenant

    Parameters (2)
    • key · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operator/tenants/{key}/blast-radiusRequires platform:tenant:read

    What 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 · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operator/tenants/{key}/exportRequires platform:tenant:export

    The tenant’s configuration, for support or migration

    Parameters (2)
    • key · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/tenants/{key}/lifecycleRequires platform:tenant:lifecycle

    Suspend, 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 · required
    • 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.

ticket 8

  • GET/v1/operator/ticketsRequires platform:ticket:read

    The 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, closed
    • priority · query — urgent, high, normal or low
    • assignee · query — Staff URN
    • unassigned · query — true for the tickets nobody owns
    • tag · query — One tag
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/ticketsRequires platform:ticket:create

    Raise 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}Requires platform:ticket:read

    One ticket, its whole thread and where it stands against the SLA

    Parameters (3)
    • tenant · path · required
    • reference · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/operator/tickets/{tenant}/{reference}/assigneeRequires platform:ticket:update

    Assign 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 · required
    • reference · path · required
    • 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}/contextRequires platform:ticket:read

    What 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 · required
    • reference · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/operator/tickets/{tenant}/{reference}/escalationsRequires platform:ticket:escalate

    Escalate 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 · required
    • reference · path · required
    • 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/operator/tickets/{tenant}/{reference}/messagesRequires platform:ticket:update

    Reply, 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 · required
    • reference · path · required
    • 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.
  • PUT/v1/operator/tickets/{tenant}/{reference}/stateRequires platform:ticket:update

    Move 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 · required
    • reference · path · required
    • 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.
ProjectX Operator · API reference · ProjectX