Skip to content
← All services

ProjectX Control Plane

Catalog, audit, metering and billing, operations, events and webhooks, and cross-pillar correlation.

283 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.

audit 21

  • GET/v1/audit/anchorsRequires platform:audit:read

    List the external anchor receipts

    Oldest first — the order the anchor chain verifies in. Each receipt carries the covered head and count, the predecessor digest and the notary signature.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/audit/anchorsRequires platform:audit:anchor

    Notarize the current chain head with the external notary

    The notary is sent a SHA-256 digest and nothing else — no tenant, no head, no counts. The receipt chains onto the previous anchor, so a deleted anchor is a gap the next one names. 409 when no notary is configured or the chain is empty.

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

    Verify the anchor history against the pinned notary key

    Three checks, each reported by name: the anchor chain holds, every signature verifies, and every covered prefix that survives in the chain still points at the event that stands there. A failure emits `platform.audit.anchor_failed`.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/audit/anomaliesRequires platform:audit:read

    List the anomalies the scanner has raised, newest first

    The durable record: kind, principal, severity, the evidence event ids from the chain, and the delivery receipt — the ITDR detection URN, or `undelivered` when no intake is configured.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/audit/anomalies/scanRequires platform:audit:scan

    Scan the audit chain for anomalies and raise them to ITDR

    Reads the window through the three detection rules (`PLT-AUD-008`): a burst of refusals, a burst of privileged actions, a run of audit exports. Every finding maps onto identity’s closed detection library and is raised to ITDR — or recorded as `undelivered` when no intake is configured, because a finding that exists only while a config flag is set is a finding that vanishes when the config does. Deduplication is durable: the record’s kind+principal+day key means rescanning the same window counts duplicates instead of paging the SOC twice. Every raise emits `platform.audit.anomaly_raised` — the watcher is written onto the bus, or the watcher is the one thing nobody watches.

    Body
    TimeWindow
    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/audit/eventsRequires platform:audit:read

    Query the audit chain

    Ordered by the chain’s own sequence, so paging is stable even when many events share a timestamp and consecutive pages concatenate to the ordered history at any page size. Every page carries a `verification` verdict for the records in it. Each record’s own seal is recomputed, always; the links between them are checked only when nothing narrowed the run, because a filtered page is a projection and the records either side of a removed one do not link. A filtered page says so rather than claiming a check it did not make.

    Parameters (12)
    • principal · query — URN of the actor.
    • resource · query — URN of the resource acted upon.
    • action · query — Action string, such as `platform:catalog:read`.
    • pillar · query — One of identity, data, video, cloud or ops.
    • decision · query — `allow`, `deny` or `error`.
    • grant_id · query — Narrows to one grant — the audit view of a JIT elevation.
    • request_id · query — Everything a single request did, across services.
    • from · query — Inclusive RFC 3339 lower bound.
    • to · query — Exclusive RFC 3339 upper bound.
    • cursor · query — Opaque cursor from the previous page.
    • limit · query — Page size, capped at the service maximum.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/audit/eventsRequires platform:audit:ingest

    Take a pillar’s sealed audit events onto the chain

    How a pillar’s events reach the chain the rest of this section reads. Each event is re-sealed onto the tenant’s chain in arrival order, because a hash chain has one writer and two pillars sealing against the head they last saw would fork it. Re-sealing changes `prev_hash` and `hash` and nothing else, and the submitted seal is recomputed first, so an event altered on the way here is refused rather than laundered. Delivery is at-least-once, so the response separates what was accepted from what the chain already held. A refused event does not fail the batch: a retry that can never succeed is a pillar spooling forever.

    Body
    AuditEventBatch
    Returns
    AuditIngestResult
    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/audit/exportRequires platform:audit:export

    Export audit events for an external SIEM or an auditor

    The chain is verified as part of the export and the verdict travels with it in `x-projectx-chain-verified`, so nobody has to take an exported file on trust.

    Parameters (13)
    • format · query — `json`, `csv` or `ocsf`. Defaults to json.
    • principal · query — URN of the actor.
    • resource · query — URN of the resource acted upon.
    • action · query — Action string, such as `platform:catalog:read`.
    • pillar · query — One of identity, data, video, cloud or ops.
    • decision · query — `allow`, `deny` or `error`.
    • grant_id · query — Narrows to one grant — the audit view of a JIT elevation.
    • request_id · query — Everything a single request did, across services.
    • from · query — Inclusive RFC 3339 lower bound.
    • to · query — Exclusive RFC 3339 upper bound.
    • cursor · query — Opaque cursor from the previous page.
    • limit · query — Page size, capped at the service maximum.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/audit/exportsRequires platform:audit:read

    List audit export receipts

    Receipts only — the filter, the event count, the SHA-256 and the chain verdict. The bytes are fetched from the download path, not listed here.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/audit/exportsRequires platform:audit:export

    Produce an audit evidence file and keep its receipt

    The only way to get Parquet, and the way to get any format with a receipt: the file is rendered, hashed (SHA-256) and stored beside the filter that produced it and the chain verdict at the time, so what an auditor receives can be checked rather than trusted.

    Body
    CreateAuditExportRequest
    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/audit/exports/{id}Requires platform:audit:read

    Read one audit export receipt

    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/audit/exports/{id}/downloadRequires platform:audit:export

    Download the evidence file

    The stored hash is recomputed over the stored bytes before they leave; a mismatch is a 409, not a file. The receipt travels in `x-projectx-content-sha256` and `x-projectx-chain-verified`.

    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/audit/legal-holdsRequires platform:audit:read

    List legal holds

    Parameters (3)
    • tenant · query — Whose holds to list. Defaults to your own.
    • include_lifted · query — Set to `true` to include holds that have already been lifted.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/audit/legal-holdsRequires platform:audit:legal_hold

    Place a legal hold over a slice of the audit chain

    Matching events survive retention expiry until the hold is lifted. Scope by principal, by resource, by time, or by all three.

    Body
    LegalHoldRequest
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/audit/legal-holds/{id}/liftRequires platform:audit:legal_hold

    Lift a legal hold

    The hold record is kept, lifted, rather than deleted: who released the matter and why is itself evidence.

    Body
    LiftHoldRequest
    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/audit/reports/{kind}Requires platform:audit:read

    Run a compliance report over a window

    The `kind` path parameter is one of `access_review`, `privileged_action` or `data_access`.

    Parameters (5)
    • kind · path · required
    • tenant · query — Whose chain to report on. Defaults to your own.
    • 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.
  • GET/v1/audit/retentionRequires platform:audit:read

    Read the audit retention window

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/audit/retentionRequires platform:audit:configure

    Set the audit retention window

    Refused below the regulatory floor. Events under legal hold outlive the window regardless of what is set here. Retention beyond the standard 730-day window is an Enterprise capability (N2): a company whose plan does not grant `audit_retention` is refused a longer window with a 403 typed `system/plan-entitlement`, while retention at or below the standard window stays open to everyone.

    Body
    RetentionPolicy
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/audit/verifyRequires platform:audit:verify

    Recompute the hash chain and report any break

    Returns the first broken link rather than a bare boolean, because "the chain is bad" is not an actionable finding and "event 4,112 does not follow event 4,111" is. A break also raises `platform.audit.chain_broken`. A break comes back with the records either side of it in `around`. Reporting a position and no records would send an investigator to the read path to ask what the broken record said, and the read path is the thing whose trustworthiness is in question.

    Body
    TimeWindow
    Returns
    ChainVerification
    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/reportsRequires platform:audit:read

    List the compliance reports a schedule has generated (H9/H11)

    Each run of a `platform.report.deliver` schedule seals a report write-once and lists it here, newest first. The rows carry the window, the row count, whether the audit chain verified and the sealed digest; the PDF bytes are fetched from the single-report download, not this list.

    Returns
    GeneratedReportList
    Parameters (2)
    • limit · query — How many to return. Defaults to 50.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/reports/{urn}Requires platform:audit:read

    Download one generated compliance report, sealed (H9/H11)

    Returns the sealed artifact: the metadata, the row count, the window, the base64 PDF bytes and the two digests. A reader hashes the decoded bytes and checks them against `pdf_sha256`, and `pdf_sha256` against `digest`, so a swapped byte or a forged record is caught. 404 when the urn is not a report of the caller’s tenant.

    Returns
    GeneratedReport
    Parameters (2)
    • urn · path · required — The resource URN, used verbatim.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

bank_account 4

  • GET/v1/bank-accountsRequires platform:bank_account:read

    List ProjectX’s receiving bank accounts

    Every account in every state, oldest first. At most one is `active` per currency, and that is the one new invoices in that currency name.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/bank-accountsRequires platform:bank_account:create

    Propose a receiving bank account

    The account is `pending_approval` and remits nothing until a second person approves it. An IBAN is checked with mod-97, because a mistyped character here sends every customer’s payment somewhere else.

    Body
    ProposeBankAccount
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/bank-accounts/{id}/approveRequires platform:bank_account:approve

    Approve a proposed bank account

    Refused with `system/dual-control` for the person who proposed it. On approval it becomes the active account for its currency and the one it replaces is retired in the same step.

    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/bank-accounts/{id}/retireRequires platform:bank_account:retire

    Retire a bank account

    No new invoice names it. Invoices already issued keep the details they were sent with. Retiring a pending account withdraws the proposal.

    Body
    RetireBankAccount
    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.

bank_transfer 5

  • POST/v1/bank-statementsRequires platform:bank_transfer:record

    Import a bank statement (CAMT.053 or MT940), with a dry run (B12)

    Parses a whole statement into incoming transfers rather than re-keying each line. The format is detected from the file; only credit lines become transfers (a debit is money out). Each line is recorded through the same path a hand-keyed one takes, so it auto-matches by its RF reference and is idempotent on the bank’s own reference — re-importing an overlapping statement records nothing new. `dry_run` parses and previews without recording: how many lines are new, how many already recorded, what each is worth, and any line that could not be read. The receiving account is resolved from the statement’s IBAN, or named in `bank_account`.

    Body
    ImportBankStatement
    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/bank-transfersRequires platform:bank_transfer:read

    List recorded bank transfers, newest first

    Parameters (2)
    • state · query — `unmatched`, `matched` or `returned`.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/bank-transfersRequires platform:bank_transfer:record

    Record a bank transfer from a statement line

    Idempotent on `bank_reference` per receiving account: re-importing a statement returns the existing record. The RF reference is looked for in `remittance_info`; when exactly one open invoice in the same currency carries it, the money is applied at once — a partial payment leaves the invoice open, an overpayment settles it and credits the rest to the customer’s prepaid balance. Otherwise the transfer waits in the unmatched queue with the reason.

    Body
    RecordBankTransfer
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/bank-transfers/{id}/mark-returnedRequires platform:bank_transfer:reconcile

    Mark an unmatched transfer as returned to the payer

    Records that the money was sent back. Never applied to anything. Refused for the person who recorded it.

    Body
    ReturnBankTransfer
    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/bank-transfers/{id}/matchRequires platform:bank_transfer:reconcile

    Match an unmatched transfer to an invoice by hand

    For a payer who quoted no reference, or the wrong one. Refused with `system/dual-control` for the person who recorded the transfer.

    Body
    MatchBankTransfer
    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.

billing_profile 7

  • GET/v1/billing-profileRequires platform:billing_profile:read

    This company’s billing country, currency, region and VAT ID

    Returns
    BillingProfile
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/billing-profileRequires platform:billing_profile:manage

    Change this company’s billing name and VAT ID

    The company name and VAT ID only (A7). Country and currency were chosen at sign-up and change through staff, because an invoice already issued in one currency cannot be followed by one in another.

    Body
    UpdateBillingProfile
    Returns
    BillingProfile
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/billing-profile/vat-checkRequires platform:billing_profile:manage

    Ask VIES about this company’s VAT ID again

    For after VIES was unavailable, or after a registration took effect (A7). The answer is kept on the profile with its consultation number; when VIES does not answer, the previous answer stands and `vat_check_error` says why.

    Returns
    BillingProfile
    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.
  • PUT/v1/billing-profiles/{tenant}Requires platform:billing_profile:provision

    Record a company’s billing profile (signup provisioner, staff)

    Written once at sign-up from the country and region the person chose (A6), and by staff afterwards. Platform tenant only. A company already invoiced in one currency cannot be moved to another here.

    Body
    ProvisionBillingProfile
    Returns
    BillingProfile
    Parameters (3)
    • tenant · 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/billing/country-currencies/{country}Requires platform:billing_profile:provision

    Resolve a billing country to its currency and region (provisioner) (C1)

    What the sign-up flow reads to turn the billing country a person chose into the currency it is invoiced in and the region it is placed in, from the staff-editable map rather than a hard-coded table. Platform tenant only.

    Parameters (2)
    • country · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/billing/signup-countries/{country}Requires platform:billing_profile:provision

    Whether a country may sign up (provisioner) (PLT-BIL-008)

    What the sign-up flow asks before anything is created: `allowed` from the commercial settings’ sign-up country rule and the embargoed countries no setting can open, with the `reason` to show the person when it is false. Platform tenant only.

    Parameters (2)
    • country · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/spend-limitRequires platform:billing_profile:read

    This company’s pay-as-you-go spend limit, earned from payment history (B11)

    A pay-as-you-go account is billed in arrears, which is a line of credit; a new one starts with a low monthly limit that rises as it pays invoices and falls back to the floor while one is overdue. The response carries the limit, the rung reached, what has been spent this month (its credit use valued at the credit price), and whether that is over the limit. A commit or enterprise account has no such limit and the response says so.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

blog 7

  • GET/v1/platform/blog/postsRequires platform:blog:read

    Every blog post in every state (staff) (K8)

    The author list: drafts, submitted, scheduled, published and archived, newest first. Optional `?state=` and `?tag=` filters. Platform tenant only.

    Returns
    BlogPostList
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/platform/blog/posts/{slug}Requires platform:blog:publish

    Delete a blog post for good (staff) (K8)

    The one irreversible act, for a mistaken draft. Prefer archive for a post that was ever live. Platform tenant only.

    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/platform/blog/posts/{slug}Requires platform:blog:read

    One blog post, whatever its state (staff) (K8)

    The editor read: the full record including the markdown body. Platform tenant only.

    Returns
    BlogPost
    Parameters (2)
    • slug · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/platform/blog/posts/{slug}Requires platform:blog:author

    Create or update a draft (staff) (K8)

    The author write. Creates the post at the slug if it is new, or overwrites the draft if it exists. A post is only editable while it is a draft or archived — a submitted, scheduled or published post must go back through submit/approve. No revision history is kept (out of scope for K8). Platform tenant only.

    Body
    BlogPostBody
    Returns
    BlogPost
    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.
  • POST/v1/platform/blog/posts/{slug}/approveRequires platform:blog:publish

    Approve a submitted post — the second person publishes it (staff) (K8)

    The second half of the two-person publish: a DIFFERENT staff member than the submitter approves, which publishes the post now, or schedules it if its `publish_at` is in the future. The submitter cannot approve their own post — a 403 typed `system/dual-control`. Platform tenant only.

    Returns
    BlogPost
    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.
  • POST/v1/platform/blog/posts/{slug}/archiveRequires platform:blog:publish

    Take a post down (staff) (K8)

    Archives a post: it was public, is no longer offered, and is not deleted — the slug and body are kept so it can be brought back through submit/approve. Platform tenant only.

    Returns
    BlogPost
    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.
  • POST/v1/platform/blog/posts/{slug}/submitRequires platform:blog:author

    Submit a draft for publication (staff) (K8)

    The first half of the two-person publish: records who submitted it and moves it to `submitted`. It is still invisible to the public; a DIFFERENT staff member must approve it to publish it. An optional `publish_at` schedules it for a future time when approved. Platform tenant only.

    Body
    BlogPostSubmit
    Returns
    BlogPost
    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.

branding 3

  • DELETE/v1/platform/brandingRequires platform:branding:write

    Drop a scope’s brand so it inherits the one above it

    Refused at platform scope. The platform brand is the row the resolver is guaranteed to find; the compiled-in default behind it exists for the endpoint being unreachable, not as somewhere to deliberately fall back to.

    Parameters (4)
    • scope · query — reseller or tenant.
    • scope_id · query — 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/platform/brandingRequires platform:branding:write

    Set the product name, mark, logo and colours for a scope

    A replace, not a patch. Resolution picks a scope whole rather than merging fields across scopes, so a brand assembled from fragments would be one nobody has seen entire — and the first place anyone would see it entire is production. What this cannot change is any identifier: `prx:`, package names, headers and environment variables are frozen by ADR-008 because the URN prefix is hashed into the audit chain.

    Body
    BrandInput
    Returns
    Brand
    Parameters (4)
    • scope · query — platform, reseller or tenant. Default platform.
    • scope_id · query — Required unless the scope is platform.
    • 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/platform/branding/scopesRequires platform:branding:read

    Read one scope’s brand exactly as stored

    The editing view, which is not the same as the rendering view. `GET /v1/platform/branding` resolves through the scope chain and always answers; this returns the row for one scope and 404s when that scope has no brand of its own, because a form needs to know the difference between "inherited" and "set to the same thing".

    Returns
    Brand
    Parameters (3)
    • scope · query — platform, reseller or tenant. Default platform.
    • scope_id · query — Required unless the scope is platform.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

budget 3

  • GET/v1/budgetsRequires platform:budget:read

    List budgets with their current spend

    `unpriced_meters` names meters that carry usage but no price. A budget that silently ignores a meter is worse than no budget, so the gap is reported rather than absorbed.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/budgets/{name}Requires platform:budget:delete

    Delete a budget

    Parameters (3)
    • 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.
  • PUT/v1/budgets/{name}Requires platform:budget:write

    Create or replace a budget

    A budget may warn or it may block. Blocking budgets refuse new spend on the scope they cover, which is a policy decision and is audited as one.

    Body
    Budget
    Parameters (3)
    • 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.

catalog 14

  • POST/v1/catalog/bulk:applyRequires platform:catalog:curate

    Apply a bulk curation, skipping entries the caller may not touch

    Every entry is authorised individually. A caller who may curate nine of ten entries changes nine and is told about the tenth.

    Body
    BulkRequest
    Returns
    BulkResult
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/catalog/bulk:planRequires platform:catalog:curate

    Preview a bulk curation without applying it

    Returns the entries that would change and the entries the caller may not touch, so a mass re-tagging can be reviewed before it happens.

    Body
    BulkRequest
    Returns
    BulkPlan
    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/catalog/censusRequires platform:catalog:search

    Count registered resources by pillar and type

    Aggregate counts only, for the deletion blast radius (`OC-TEN-006`). Like the facet counts, and for the same reason, this is not entitlement-filtered: it reveals that forty cameras exist, not which.

    Parameters (2)
    • tenant · query — Whose catalog to count. Defaults to your own.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/catalog/entriesRequires platform:catalog:register

    Register a resource in the catalog

    Idempotent by URN, and preserves the original creation time, so a pillar may re-register its inventory freely. Invariant 6 makes this every pillar’s obligation rather than the catalog’s.

    Body
    CatalogEntryInput
    Returns
    CatalogEntry
    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/catalog/entries/{urn}Requires platform:catalog:remove

    Remove an entry

    For resources that genuinely no longer exist. To wind one down while keeping its history, deprecate and retire it instead.

    Parameters (3)
    • urn · path · required — The resource URN, used verbatim.
    • 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/catalog/entries/{urn}Requires platform:catalog:read

    Fetch one catalog entry by URN

    Returns
    CatalogEntry
    Parameters (2)
    • urn · path · required — The resource URN, used verbatim.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PATCH/v1/catalog/entries/{urn}Requires platform:catalog:curate

    Curate an entry’s description, owner, tags or classification

    Body
    CatalogEntryPatch
    Returns
    CatalogEntry
    Parameters (3)
    • urn · path · required — The resource URN, used verbatim.
    • 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/catalog/entries/{urn}/accessRequires platform:catalog:read

    Who can reach this resource, and through which grant

    Computed from the PDP on every call rather than stored, because a cached answer to "who can access this" is a wrong answer to a security question. `truncated` says when the list is a sample.

    Parameters (2)
    • urn · path · required — The resource URN, used verbatim.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/catalog/entries/{urn}/activityRequires platform:catalog:read

    Who has touched this resource lately, and how often

    Read from the audit chain rather than a counter, so the popularity signal and the access review agree with one another.

    Parameters (3)
    • urn · path · required — The resource URN, used verbatim.
    • window_days · query — How far back to look. Defaults to 30.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/catalog/entries/{urn}/deprecateRequires platform:catalog:deprecate

    Start an entry’s notice period

    Records the reason, the replacement if there is one, and the date the entry may be retired. Consumers keep working throughout; the notice is what gives them time to move.

    Body
    DeprecateRequest
    Returns
    CatalogEntry
    Parameters (3)
    • urn · path · required — The resource URN, used verbatim.
    • 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/catalog/entries/{urn}/reinstateRequires platform:catalog:deprecate

    Return a deprecated or retired entry to active service

    Body
    ReinstateRequest
    Returns
    CatalogEntry
    Parameters (3)
    • urn · path · required — The resource URN, used verbatim.
    • 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/catalog/entries/{urn}/retireRequires platform:catalog:deprecate

    Retire a deprecated entry once its notice period has run

    Refused while the notice period is still open, and refused outright if the entry was never deprecated.

    Body
    RetireRequest
    Returns
    CatalogEntry
    Parameters (3)
    • urn · path · required — The resource URN, used verbatim.
    • 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/catalog/facets/{facet}Requires platform:catalog:search

    Count entries by pillar, type, classification, lifecycle or owner

    Drives the filter sidebar. Counts are of the whole catalog, not of one search.

    Parameters (2)
    • facet · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/catalog/searchRequires platform:catalog:search

    Search the catalog across every pillar

    Results are filtered by what the calling principal may see, so two people running the same search get different answers. `excluded_count` reports how many matches were withheld — the fact that something exists is disclosed, its contents are not.

    Body
    CatalogSearchRequest
    Returns
    CatalogSearchResult
    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.

commercial_settings 5

  • GET/v1/platform/commercial-settingsRequires platform:commercial_settings:read

    The commercial settings in force (staff) (PLT-BIL-008)

    Which deposit methods are on (globally, and the countries each is off in) and which one a form selects first; who may sign up (everyone, an allow-list or a block-list, never the embargoed countries in `always_blocked_countries`); the deposit minimum and the first-deposit bonus. Version 0 is the built-in default from the deployment’s environment. Platform tenant only.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/commercial-settings/proposalsRequires platform:commercial_settings:read

    Commercial settings change proposals (staff) (PLT-BIL-008)

    Newest first, every state. `pending=true` narrows to those still awaiting a second person. Platform tenant only.

    Parameters (2)
    • pending · query — Set to `true` to return only proposals still awaiting approval.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/commercial-settings/proposalsRequires platform:commercial_settings:manage

    Propose a change to the commercial settings (staff) (PLT-BIL-008)

    The whole document, validated now and held `pending_approval` until a different person approves it. Refused if it would switch every deposit method off, select a default method that is off, allow an embargoed country, or set a bonus floor below the deposit minimum. Platform tenant only.

    Body
    ProposeCommercialSettings
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/platform/commercial-settings/proposals/{proposalId}/approveRequires platform:commercial_settings:approve

    Approve a commercial settings proposal (staff) (PLT-BIL-008)

    The second person agrees: the proposed document is published as the next version and every consumer reads it on its next request. Refused for the proposer (403 `system/dual-control`), and refused (409) when another version was published after the proposal was written. Platform tenant only.

    Parameters (3)
    • proposalId · 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/platform/commercial-settings/proposals/{proposalId}/rejectRequires platform:commercial_settings:approve

    Reject a commercial settings proposal (staff) (PLT-BIL-008)

    The second person declines; nothing is published. Refused for the proposer, like approval. Platform tenant only.

    Body
    RejectCommercialSettings
    Parameters (3)
    • proposalId · 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.

compliance 3

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

    The Article 30 record of processing activities

    Generated from the unified catalog and the lineage graph rather than maintained by hand. Every activity the record could not complete is listed in `gaps`, so an incomplete record says so rather than looking finished.

    Parameters (2)
    • tenant · query — Whose record. Defaults to your own.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/compliance/dpia/{urn}Requires platform:compliance:read

    The DPIA support pack for one resource

    What is processed, where, why, for how long, and who has actually touched it — kept separate from who *could* touch it, because the difference 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/compliance/evidence-packsRequires platform:compliance:generate

    Generate a sealed evidence pack for an audit window

    Bundles the chain verification, the three compliance reports, the Article 30 record and the legal holds in force, sealed with a SHA-256 digest over a canonical form so the recipient can verify it reached them intact.

    Body
    TimeWindow
    Parameters (3)
    • tenant · query — Whose pack. Defaults to your own.
    • 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.

contact 2

  • GET/v1/contact-messagesRequires platform:contact:read

    Contact-form submissions, for the support desk intake (staff)

    Every message the public form accepted, newest first. `state=pending` is the intake the operator support desk sweeps into tickets with an SLA; a converted message names the ticket it became. Platform tenant only.

    Parameters (3)
    • state · query — `pending` or `converted`; omit for both.
    • limit · query — Cap the page. Default 200.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/contact-messages/{id}/convertRequires platform:contact:manage

    Mark a contact message as taken into the support desk

    The desk raises the ticket first and records the conversion second, so a message is never both pending and ticketed and a retried intake sees done work. Already-converted answers the stored record. Platform tenant only.

    Body
    ContactMessageConvert
    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.

credit_note 4

  • GET/v1/credit-notesRequires platform:credit_note:read

    List credit notes, newest first

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credit-notes/{number}Requires platform:credit_note:read

    Fetch one credit note

    Parameters (2)
    • number · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credit-notes/{number}/documentRequires platform:credit_note:read

    Download the sealed PDF of a credit note

    The credit note as a sealed, immutable PDF, mirroring the credit note which already cannot exceed the invoice it corrects. Generated once on first read and stored.

    Parameters (2)
    • number · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/invoices/{number}/credit-notesRequires platform:credit_note:issue

    Issue a credit note against an invoice

    Money comes off an invoice by crediting it, never by editing it. The credit note mirrors the invoice’s tax treatment and cannot, across every note issued against the invoice, exceed what the invoice was for.

    Body
    IssueCreditNote
    Parameters (3)
    • number · 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.

credits 33

  • GET/v1/commitmentsRequires platform:credits:read

    This company’s committed-use contracts, and the active one (N4)

    Every committed-use contract the company has had, newest first, with the active one called out. A committed-use contract is a 1- or 3-year spend commitment at a term discount: the company draws every credit of usage at the committed rate, usage beyond the commitment is billed at the same rate, and an underspend is trued up at term end.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/commitmentsRequires platform:credits:purchase

    Open a committed-use contract (N4)

    Commit to spend at least an amount over a 1- or 3-year term in return for a committed-rate discount off list that every credit of usage draws at. A company may have one active contract at a time; opening a second while one runs is refused.

    Body
    OpenCommitment
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/commitments/{id}/cancelRequires platform:credits:purchase

    Cancel a committed-use contract before its term ends (N4)

    Early termination: record the cancelled state and the reason. The commercial consequence of an early exit is settled separately.

    Body
    CancelCommitment
    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/commitments/{id}/true-upRequires platform:credits:settle

    True up a committed-use contract at term end (N4)

    A finance act. At or after the term’s end, settle the contract: compute the shortfall of an underspend (the company committed to spend it, so it is owed) and the overage of an overspend (already drawn at the committed rate), record both and mark the contract completed. Refused before the term ends. The shortfall is what the final invoice bills (N10).

    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/commitments/allRequires platform:credits:read_any

    Every company’s committed-use contracts, as staff see them (N8)

    Platform tenant only. Every committed-use contract across every company, newest first, for the operator’s commit-contracts view: who is committed to what over which term, how much has been drawn down, and which have been trued up or cancelled. A read; the per-tenant routes own every write.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/commitments/ladderRequires platform:credits:read

    The committed-use term discount ladder (N4)

    The published rungs, per term: the longer the term and the larger the commitment, the deeper the committed-rate discount off list. Read by the pricing page.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credit-ledgers/{tenant}Requires platform:credits:read_any

    A company’s credit ledger, as staff see it

    Platform tenant only (B9).

    Parameters (2)
    • tenant · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/credit-ledgers/{tenant}/deposit-bonus/withholdRequires platform:credits:grant

    Withhold the first-deposit bonus from a company (provisioner, staff)

    Before the company deposits: a sign-up on a disposable address, or a staff judgement. The company can still deposit and use credits; its first deposit earns no bonus. Refused once the bonus was granted (refund the deposit to reverse it). Platform tenant only. Withholding twice changes nothing.

    Body
    WithholdDepositBonus
    Parameters (3)
    • tenant · 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/credit-ledgers/{tenant}/entries/{id}/refundRequires platform:credits:settle

    Refund a settled deposit, reversing its first-deposit bonus (staff)

    A customer refund or a chargeback against a settled credit purchase. The deposit’s unspent credits are drawn as a refund worth their share of the money paid (what was spent stays spent), and if this deposit earned the first-deposit bonus, what is left of the bonus is taken back and the bonus is marked reversed. Platform tenant only. Idempotent on the deposit.

    Body
    RefundDeposit
    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/credit-ledgers/{tenant}/entries/{id}/settleRequires platform:credits:settle

    Mark a credit purchase settled (staff)

    Once the money behind a purchase has arrived (B2): its credits become transferable and refundable. Platform tenant only. Settling twice changes nothing.

    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/credit-ledgers/{tenant}/grantsRequires platform:credits:grant

    Grant starter or promotional credits to a company (provisioner, staff)

    Mints a `starter_grant` or `promotional` grant into a company’s ledger (B3, L3): credits that are spendable, non-transferable, and lapse on the date given. Platform tenant only. Idempotent on `id`, so a retried sign-up grants once.

    Body
    GrantCredits
    Parameters (3)
    • tenant · 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/credit-standings/{tenant}Requires platform:credits:read_any

    Whether a company may provision, for a pillar or staff

    The check a pillar makes before creating anything metered: `may_provision` is false while the company’s credit balance is empty, with a `reason` to show the person who asked. Platform tenant only.

    Parameters (2)
    • tenant · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credit-transfersRequires platform:credits:transfer_review

    Credit transfers across every company, for staff review (B7)

    Platform tenant only. Defaults to those held for review; `state` narrows to any one state.

    Parameters (2)
    • state · query — One of proposed, held, accepted, cancelled, rejected, lapsed. Default held.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/credit-transfers/{id}/reviewRequires platform:credits:transfer_review

    Release or refuse a held credit transfer (staff) (B7)

    Platform tenant only. `release` returns the transfer to proposed so the recipient can accept; `reject` ends it. Only a transfer that is held for review.

    Body
    ReviewCreditTransfer
    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/creditsRequires platform:credits:read

    This company’s Platform Credits: what it holds and every movement

    The credit ledger (B2), newest first, with what it adds up to: credits spendable now, the part that is paid and settled (transferable), settled purchases (refundable), purchases not yet settled, and starter or promotional credits with when each lot lapses.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credits/commit-ladderRequires platform:credits:read

    The commit discount ladder

    The published rungs (B5): the more a company commits up front, the more bonus credits the money buys. Read by the pricing page and the buy-credits preview.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credits/crypto-checkoutsRequires platform:credits:read

    List this company’s crypto checkouts and confirmation state

    Every BTC or USDC checkout this company initiated, newest first. Amounts are integer base units represented as strings. The address and transaction hash are public payment details; no wallet key or seed material is exposed.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credits/deposit-bonusRequires platform:credits:read

    The first-deposit bonus: the rule, and what became of this company’s

    The first settled deposit of at least the minimum earns promotional credits once per company, lapsing after the stated days (250 credits on a 100-credit deposit, for 90 days, by default). `state` is absent until something happened: `granted`, `reversed` (the deposit that earned it was refunded) or `withheld`.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/credits/depositsRequires platform:credits:purchase

    Deposit money into credits (pay as you go)

    The money buys credits at this company’s list price, plus the commit-ladder bonus for a large deposit; a deposit below 100 credits’ worth is refused. A card or SEPA deposit charges the stored method (or the one named): 201 with the settled purchase when the charge goes straight through, 202 with the payment when it needs Strong Customer Authentication or settles later, and the credits land via `POST /v1/payments/:id/credit-top-up` once it has. A transfer deposit is recorded unsettled with an RF reference and the account to pay; the credits are spendable at once and settle when the transfer quoting the reference is matched.

    Body
    DepositCredits
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/credits/deposits/{id}/crypto-confirmRequires platform:credits:purchase

    Confirm a pending crypto deposit from the blockchain watcher (task 17)

    Called by the NBXplorer watcher (BTC) or the Base RPC listener (USDC) once the on-chain transaction is seen. The platform records the tx hash and confirmation count; when the required threshold is reached it settles the purchase entry and may grant the first-deposit bonus. Idempotent: re-delivering the same tx hash advances the confirmation count but never double-credits.

    Body
    ConfirmCryptoDeposit
    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/credits/deposits/methodsRequires platform:credits:read

    How this company may pay a deposit

    The deposit methods open to this company — those staff have switched on, less any switched off in its billing country — and the one a deposit form should select first. A deposit by any other method is refused.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credits/deposits/minimumRequires platform:credits:read

    The smallest deposit this company may make, per currency

    A deposit must buy at least 100 credits at this company’s list price: €10, £9 or $11 at the default rate card. Read from the rate card, so it follows a change to the price of a credit.

    Parameters (2)
    • currency · query — ISO 4217 code. Defaults to EUR.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/credits/purchasesRequires platform:credits:purchase

    Buy credits up front at the commit discount (B5)

    The money buys credits at this company’s list price plus a bonus from the commit ladder for the size of the purchase. Recorded as one purchase in the ledger, which never expires; it starts unsettled until the payment arrives (card capture, or a matched bank transfer). The amount is what the company pays, so a refund returns the cash and not the bonus.

    Body
    BuyCredits
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/credits/quoteRequires platform:credits:read

    Price a list of quantities in credits and money

    The calculator’s arithmetic, which is the invoice’s (B1): each line in credits at this company’s rate card and in the currency asked for. A line the card does not rate is listed under `unrated` rather than priced at zero.

    Body
    CreditQuoteRequest
    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/credits/rate-cardRequires platform:credits:read

    The credit rate card this company is rated by

    How many credits a unit of each meter is worth, per SKU where the kind of work matters, and what a credit costs per currency (B1). The company’s private card if it has one, otherwise the platform default.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credits/standingRequires platform:credits:read

    Whether this company may provision, from its credit balance

    Pay as you go: `funded`, `low` (at or under 20% of the last deposit), `empty` (new resources are refused; running compute pauses at `pauses_at`, 72 hours after the balance emptied) or `paused` (metered compute stopped, nothing deleted; a deposit starts it again). A company billed as Enterprise is `exempt`.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/credits/transfersRequires platform:credits:read

    This company’s credit transfers, sent and received (B7)

    Every transfer this company proposed or was offered, newest first, in each state: proposed, held for review, accepted, cancelled, rejected or lapsed.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/credits/transfersRequires platform:credits:transfer

    Offer to transfer credits to another company (B7)

    The sender’s admin proposes; nothing moves until the recipient accepts. The sender must hold enough settled, paid credits (gifts and unpaid purchases cannot be transferred), stay within the rolling 30-day cap, and both companies must be verified. A transfer over 50,000 credits or to a company younger than seven days is held for ProjectX staff. The offer lapses in 14 days if unaccepted.

    Body
    ProposeCreditTransfer
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/credits/transfers/{id}/acceptRequires platform:credits:transfer

    Accept a credit transfer offered to this company (B7)

    The recipient’s half of the maker-checker, and the only call that moves credits: drawn from the sender and added to this company in one step. Only the receiving company can accept, and only an offer that is proposed (not held for review) and not lapsed. Accepting twice changes nothing.

    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/credits/transfers/{id}/cancelRequires platform:credits:transfer

    Withdraw a credit transfer before it is accepted (B7)

    Only the sending company, and only while the transfer is still proposed or held — a transfer already accepted has moved and cannot be cancelled.

    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/credits/usageRequires platform:credits:read

    This company’s usage counted in Platform Credits (B8)

    What the company has used this month in credits, not what it holds: credits used today and month-to-date, a straight-line forecast of the month at the current rate, and the breakdown by pillar, project and meter — and, for compute usage, by product and by SKU grouped the way the public price pages are (N5). Each breakdown reconciles to the rated total. A meter the rate card does not price is named under `unrated` rather than counted as free, because usage with no rate is spend the credit total cannot see.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/deposit-bonusesRequires platform:credits:read_any

    Every company’s first-deposit bonus: grants, reversals, holds (staff)

    The rule this deployment runs and one row per company that has a bonus record, newest first: granted (with the deposit that earned it and when it lapses), reversed (with the unspent credits taken back) or withheld (with why). Platform tenant only.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/spend-limits/{tenant}Requires platform:credits:read_any

    A company’s pay-as-you-go spend limit, as staff see it (B11)

    Platform tenant only.

    Parameters (2)
    • tenant · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

currency_map 2

  • GET/v1/billing/country-currenciesRequires platform:currency_map:read

    The country→currency and region map (staff) (C1)

    The staff-editable table that decides, from a company’s billing country, which of the launch currencies it is invoiced in and which region it is placed in by default. The built-in default is returned until staff publish one. Platform tenant only.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/billing/country-currenciesRequires platform:currency_map:manage

    Publish the country→currency and region map (staff) (C1)

    Replaces the map whole, like a rate card, so one map always explains how any country is billed. A rule may only assign one of the launch currencies and regions, so the map can never route a company to a currency with no receiving bank account. Platform tenant only.

    Body
    PutCountryCurrencies
    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.

deployment 1

  • GET/v1/platform/releaseRequires platform:deployment:read

    What version this service is running and what schema it is on

    The applied migrations are dated and ordered, which makes them the only genuine release history the platform has: nothing records when a *version* was deployed, and this says so in `gaps` rather than presenting an uptime as a deploy date. Drifted entries are the ones to read first — a migration applied under a different checksum than this build carries means two environments share a version number and not a schema.

    Returns
    ReleaseReport
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

dunning 6

  • GET/v1/deletion-certificatesRequires platform:dunning:read

    List deletion certificates

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/dunningRequires platform:dunning:read

    List dunning records and their stage

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/dunningRequires platform:dunning:manage

    Open dunning on an unpaid invoice

    Idempotent by invoice: opening dunning on an invoice that already has it returns the existing record rather than resetting the clock, so a second reminder job cannot un-suspend an account by starting over.

    Body
    OpenDunning
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/dunning/{number}/advanceRequires platform:dunning:manage

    Advance a dunning record to the stage its schedule dictates

    The stage is computed from the due date and the clock, never guessed forward one step, so a reminder job that ran late lands on the right stage. Soft suspension retains data; hard suspension starts the retention countdown.

    Parameters (3)
    • number · 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/dunning/{number}/deleteRequires platform:dunning:delete

    Delete the account at the end of the retention window and issue a certificate

    Only from hard suspension, and only once the retention window has run. Returns a sealed deletion certificate whose digest the customer’s own tooling can recompute.

    Parameters (3)
    • number · 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/dunning/{number}/resolveRequires platform:dunning:manage

    Record that the invoice was paid and un-suspend the account

    Parameters (3)
    • number · 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.

entitlement 9

  • GET/v1/compliance/profileRequires platform:entitlement:read

    This company’s compliance profile (N2)

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/compliance/profileRequires platform:entitlement:manage

    Set this company’s compliance profile (N2)

    The frameworks the company attests to and where its data must reside. An Enterprise capability: refused with `system/plan-entitlement` unless the plan grants `compliance_profile`. Does not touch the existing `/v1/compliance/*` evidence routes, which stay open to every company.

    Body
    ComplianceProfileInput
    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/customer-keysRequires platform:entitlement:read

    This company’s customer-managed-keys config (N2)

    Records whether customer-managed keys are enabled and a reference to the key — never key material. The data-plane encryption integration that would use the reference is future work; this is the recorded intent. Defaults to disabled.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/customer-keysRequires platform:entitlement:manage

    Set this company’s customer-managed-keys config (N2)

    Enable customer-managed keys and record a reference to the key (a vault path or KMS id — never key material). An Enterprise capability: refused with `system/plan-entitlement` unless the plan grants `customer_managed_keys`. This records the intent and reference only; the data-plane encryption integration is future work.

    Body
    CustomerKeysInput
    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/offboarding/reach/{principal}Requires iam:entitlement:read

    Everything one principal can reach, across every pillar

    Entitlements from the PDP, ownership from the catalog, credentials and delegated agents from the identity plane — the three sources that each know something the other two do not. Read-only: this is what an access review asks and what an offboarding sweep shows its approver.

    Parameters (2)
    • principal · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/private-networkingRequires platform:entitlement:read

    This company’s private-networking config (N2)

    Records whether private networking is enabled and the CIDRs access should be fenced to. The data-plane networking integration is future work; this is the recorded intent. Defaults to disabled.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/private-networkingRequires platform:entitlement:manage

    Set this company’s private-networking config (N2)

    Enable private networking and record the CIDRs it should be reachable from. An Enterprise capability: refused with `system/plan-entitlement` unless the plan grants `private_networking`. This records the intent and config only; the data-plane networking integration is future work.

    Body
    PrivateNetworkingInput
    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/sla-tierRequires platform:entitlement:read

    This company’s SLA tier (N2)

    The negotiated SLA tier and its availability target, distinct from the claim-based SLA service credits at `/v1/sla-credits`, which stay open to everyone. Defaults to the standard tier when none is assigned.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/sla-tierRequires platform:entitlement:manage

    Set this company’s SLA tier (N2)

    Record which SLA tier the company is on and the availability it targets. An Enterprise capability: refused with `system/plan-entitlement` unless the plan grants `sla`. Does not touch the existing `/v1/sla-credits` claim workflow.

    Body
    SlaTierInput
    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.

event 3

  • POST/v1/correlateRequires platform:event:read

    Correlate events across pillars on principal, resource, time or location

    This is what answers "who entered the server room without badging in": badge events from identity joined to detections from video. Pillars the caller may not read are dropped when the plan is built, never after the data is fetched, and the response names them in `plan.excludedPillars` so a partial answer is never mistaken for a complete one.

    Body
    CorrelationRequest
    Returns
    CorrelationResult
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/eventsRequires platform:event:publish

    Publish an event onto the bus

    The envelope is stamped by the service — event id, time, tenant, trace — and the type is checked against the catalog. Events partition by tenant and resource, so a resource’s events stay in order.

    Body
    PublishEventRequest
    Returns
    EventEnvelope
    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/events/catalogRequires platform:event:read

    List every event type the platform can emit, grouped by pillar

    Publishing a type that is not in this catalog is refused, so a webhook subscription can be checked against it before anything is wired up.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

feature_flag 6

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

    This company’s resolved feature flags

    The resolved on/off answer for every flag, for your own company. You see only the booleans — not the rollout percentages or any other company’s overrides. A console or a service checks this to decide whether a feature is on for you.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/feature-flagsRequires platform:feature_flag:read

    Every feature flag, with its rollout and per-company overrides (staff)

    The full flag records: default, rollout percentage and the per-company override map. This is the management view and is platform-tenant only — a company cannot read it. A company reads its OWN resolved booleans at `GET /v1/feature-flags`.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/platform/feature-flags/{key}Requires platform:feature_flag:set

    Delete a feature flag (staff)

    Removes the flag entirely. A company evaluating it afterwards sees it absent rather than off. Platform tenant only.

    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.
  • PUT/v1/platform/feature-flags/{key}Requires platform:feature_flag:set

    Create or replace a feature flag (staff)

    A replace, not a patch — the body carries the whole flag. Evaluation precedence is a per-company override, then the percentage rollout, then the default. The rollout is deterministic and monotonic: raising the percentage only ever adds companies, never flips one out. Platform tenant only.

    Body
    FeatureFlagSet
    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/platform/feature-flags/{key}/overrides/{tenant}Requires platform:feature_flag:set

    Clear one company’s override on a flag (staff)

    Removes a company’s pin, so it falls back to the rollout or the default. Clearing an override that was never set is a no-op. Platform tenant only.

    Parameters (4)
    • key · path · required
    • tenant · 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/platform/feature-flags/{key}/overrides/{tenant}Requires platform:feature_flag:set

    Pin one company’s answer for a flag (staff)

    Sets one company’s override — `enabled` wins over the rollout and the default for exactly this company. The rest of the flag is left untouched. Platform tenant only.

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

feedback 2

  • POST/v1/feedbackRequires platform:feedback:submit

    Send in-product feedback about the product (any signed-in user)

    A short note, optionally with a sentiment and the console page it was sent from. Stored and readable by operators — it is not a mailto. The feedback is about your own company; the tenant is taken from your token.

    Body
    FeedbackSubmission
    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/platform/feedbackRequires platform:feedback:read

    Every piece of in-product feedback, newest first (staff)

    The operator inbox: feedback from every company, with the tenant, sentiment, message, page and when. Platform tenant only.

    Returns
    FeedbackList
    Parameters (2)
    • limit · query — Cap the page. Default 200.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

fx_rate 2

  • GET/v1/billing/fx-ratesRequires platform:fx_rate:read

    The FX reference table (staff) (C3)

    The dated, ECB-seeded reference rates — base EUR, one row per quote currency per working day — that the credit-price drift check (C2) reads to judge whether the hand-set per-currency credit prices still track one another. It is a reference only: nothing in the money path converts a customer’s money between currencies. The built-in default is returned until staff publish the real ECB figures. Platform tenant only.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/billing/fx-ratesRequires platform:fx_rate:manage

    Publish the FX reference table (staff) (C3)

    Replaces the table whole with the ECB’s reference rates. A past day’s rate does not change, so a new working day is new rows; the table rejects two rows for one currency on one day. The drift check reads the most recent rate per currency. Platform tenant only.

    Body
    PutFxRates
    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.

glossary 3

  • GET/v1/glossaryRequires platform:glossary:read

    List business glossary terms

    Terms carry synonyms, which is how a search for "revenue" reaches a table called `fct_bookings`.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/glossary/{key}Requires platform:glossary:write

    Delete a glossary term

    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.
  • PUT/v1/glossary/{key}Requires platform:glossary:write

    Create or replace a glossary term

    Body
    GlossaryTermInput
    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.

invoice 5

  • GET/v1/invoicesRequires platform:invoice:read

    List invoices, newest first

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/invoicesRequires platform:invoice:generate

    Generate one invoice for a month

    One invoice covers every pillar the tenant used — identity seats, query bytes, camera hours and VPS hours arrive on a single document. Send an `Idempotency-Key`: a retried generation must not produce a second invoice.

    Body
    GenerateInvoiceRequest
    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/invoices/{number}Requires platform:invoice:read

    Fetch one invoice with its lines

    Parameters (2)
    • number · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/invoices/{number}/documentRequires platform:invoice:read

    Download the sealed PDF of an invoice

    The invoice as a sealed, immutable PDF. Generated once on first read and stored; a second read returns the identical bytes. The `application/pdf` body is the file itself.

    Parameters (2)
    • number · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/invoices/{number}/receiptRequires platform:invoice:read

    Download the sealed PDF receipt for a paid invoice

    A receipt acknowledges that the invoice was paid. It is refused with a 409 for an invoice that is not paid: a receipt for an unpaid invoice is a false document.

    Parameters (2)
    • number · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

lineage 3

  • GET/v1/lineage/{urn}Requires platform:lineage:read

    Walk the lineage graph from one resource

    Parameters (4)
    • urn · path · required — The resource URN, used verbatim.
    • direction · query — `upstream` or `downstream`. Defaults to downstream.
    • depth · query — How many hops to follow. Defaults to the graph’s own cap.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/lineage/{urn}/impactRequires platform:lineage:read

    What breaks if this resource changes

    The downstream closure, grouped by pillar and by owner, so the notice goes to people rather than to URNs.

    Parameters (2)
    • urn · path · required — The resource URN, used verbatim.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/lineage/edgesRequires platform:lineage:write

    Record lineage edges between resources

    Edges are directed from source to target and may cross pillars: a camera feeds a detection table as legitimately as one table feeds another.

    Body
    LineageEdges
    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.

mail_provider 12

  • GET/v1/platform/mail-domainsRequires platform:mail_provider:read

    The sending domains and their recorded DKIM selectors (staff) (K6)

    The distinct domains the platform sends from, derived from the configured providers’ and per-stream routes’ From addresses, each with the DKIM selector it would be checked with (an operator-recorded one, or the `default` fallback). No DNS is resolved here — this is the list the console shows before a live check. Platform tenant only.

    Returns
    MailDomainList
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/platform/mail-domains/{domain}Requires platform:mail_provider:configure

    Record the DKIM selector a sending domain signs with (staff) (K6)

    The DKIM check needs to know the selector the relay or provider signs with, which only the operator knows. This records it per domain; a domain with none is checked with the `default` selector. Platform tenant only.

    Body
    MailDomainSelector
    Parameters (3)
    • domain · 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/platform/mail-domains/{domain}/verifyRequires platform:mail_provider:read

    Resolve a domain’s DNS and check SPF, DKIM and DMARC (staff) (K6)

    The live check. Resolves the SPF record at the domain root, the DKIM record at `<selector>._domainkey.<domain>` for the domain’s selector, and the DMARC record at `_dmarc.<domain>`, and returns a pass/warn/fail verdict for each with a short guidance sentence and the record found, plus an overall verdict (the worst of the three). Idempotent and bodyless — a GET that does a network read. Platform tenant only.

    Returns
    MailDomainCheck
    Parameters (2)
    • domain · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/mail-providersRequires platform:mail_provider:read

    The configured mail providers and which is active (staff)

    Records only. The key never leaves the vault, and a record carries a fingerprint instead so that two keys can be compared without either being seen. Platform tenant only.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/platform/mail-providers/{provider}Requires platform:mail_provider:configure

    Remove a mail provider and destroy its key (staff)

    The record is removed and its key deleted from the vault. A mail provider is platform configuration, not an audit subject, so unlike a cloud credential the record does not survive. Platform tenant only.

    Parameters (3)
    • provider · 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/platform/mail-providers/{provider}Requires platform:mail_provider:configure

    Configure or replace a mail provider (staff)

    The key goes to the vault and the response never echoes it. Replacing an existing provider rotates its key in place and keeps its active state, so re-keying the live provider does not take email offline. Platform tenant only.

    Body
    MailProviderConfig
    Parameters (3)
    • provider · 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/platform/mail-providers/{provider}/activateRequires platform:mail_provider:configure

    Make one mail provider the active one (staff)

    Exactly one provider is active, so the previous one is demoted in the same change. The active provider is the one the service builds its mailer from at startup. Platform tenant only.

    Parameters (3)
    • provider · 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/platform/mail-providers/{provider}/testRequires platform:mail_provider:read

    Check a mail provider’s configuration (staff)

    Confirms the record is complete and its key is in the vault. It does NOT send through the provider — a live send cannot be verified without contacting the provider, so this reports `verified: false` with a plain statement rather than a result it did not earn. Platform tenant only.

    Parameters (3)
    • provider · 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/platform/mail-routesRequires platform:mail_provider:read

    The configured per-stream mail routes (staff)

    Each route is a stream and its ordered providers — the primary first, then fallbacks. A stream absent here has no explicit route and falls back to the active provider. Platform tenant only.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/platform/mail-routes/{stream}Requires platform:mail_provider:configure

    Set the providers a mail stream is routed through (staff)

    The first entry is the primary; the rest are fallbacks tried in order when one throws. Optional weights split a message across equally-ranked primaries for provider warm-up. Every provider named must already be configured. Platform tenant only.

    Body
    MailRouteConfig
    Parameters (3)
    • stream · 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/platform/mail/suppressionsRequires platform:mail_provider:read

    The mail suppression list (staff) (K4)

    Every address the platform will not send to, and why: a hard bounce, a spam complaint, an unsubscribe, or a manual entry. Per stream — a marketing suppression does not silence transactional mail. Optionally filter by `stream`. Platform tenant only.

    Returns
    MailSuppressionList
    Parameters (3)
    • stream · query — Only this stream’s suppressions: transactional or marketing.
    • limit · query — At most this many, newest first.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/platform/mail/suppressions/{stream}/{address}Requires platform:mail_provider:configure

    Un-suppress one address on one stream (staff) (K4)

    Lifts a suppression by hand — the way back in for a recipient who fixed their mailbox. Idempotent: removing one that is not there is a no-op. Platform tenant only.

    Parameters (4)
    • stream · path · required
    • address · 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.

mail_template 6

  • GET/v1/platform/mail-templatesRequires platform:mail_template:read

    The active mail template overrides, one per key and locale (staff) (K5)

    Every active staff-authored override. A key/locale absent here uses the built-in default template. Platform tenant only.

    Returns
    MailTemplateList
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/platform/mail-templates/{key}/{locale}Requires platform:mail_template:configure

    Save a new version of a template override (staff) (K5)

    Creates a NEW version rather than mutating one, so older versions are retained for rollback. A saved version is not active until it is activated. Platform tenant only.

    Body
    MailTemplateBody
    Parameters (4)
    • key · path · required
    • locale · 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/platform/mail-templates/{key}/{locale}/activateRequires platform:mail_template:configure

    Make one version of a template the active one (staff) (K5)

    Activating an older version is how an operator rolls back. Exactly one version per key and locale is active; the previous active is deactivated in the same change. Platform tenant only.

    Body
    MailTemplateActivate
    Parameters (4)
    • key · path · required
    • locale · 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/platform/mail-templates/{key}/{locale}/versionsRequires platform:mail_template:read

    The version history of one template key and locale (staff) (K5)

    Every saved version, newest first, so an operator can see history and roll back by activating an older one. Platform tenant only.

    Returns
    MailTemplateList
    Parameters (3)
    • key · path · required
    • locale · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/mail-templates/previewRequires platform:mail_template:read

    Render a template against sample context, without sending (staff) (K5)

    A pure render for the console preview pane: the active override, the built-in default, or an unsaved override handed in via `subject`/`text`/`html`. Nothing is queued or sent. Platform tenant only.

    Body
    MailTemplatePreview
    Returns
    MailTemplateRendered
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/platform/mail-templates/test-sendRequires platform:mail_template:configure

    Queue a one-off test send of a template to a chosen address (staff) (K5)

    Renders the template against sample context and queues a REAL one-off message to the address you type, into the normal transactional outbox, so it goes out through the configured provider on the next drain. It does not fake delivery and does not bypass suppression or routing. Platform tenant only.

    Body
    MailTemplateTestSend
    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.

meter 2

  • GET/v1/metersRequires platform:meter:read

    List every meter the platform can charge for

    The catalog is frozen in code, not configured per tenant, so a meter means the same thing on every invoice.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/meters/eventsRequires platform:meter:ingest

    Ingest a batch of meter events

    Deduplicated on the event’s idempotency key, so a pillar retrying after a timeout cannot bill a customer twice. The response separates what was accepted from what was recognised as a repeat.

    Body
    MeterEventBatch
    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.

newsletter 18

  • GET/v1/platform/newsletter/campaignsRequires platform:newsletter:read

    Every newsletter campaign (staff) (K9)

    The campaigns, newest first. Optional `?state=` filter. Platform tenant only.

    Returns
    NewsletterCampaignList
    Parameters (2)
    • state · query — draft, scheduled, sending, sent or cancelled.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/newsletter/campaignsRequires platform:newsletter:author

    Create a campaign draft (staff) (K9)

    Creates a draft campaign targeting a list (optionally narrowed to a segment). `body` is markdown rendered to safe HTML and branded at send time. Platform tenant only.

    Body
    NewsletterCampaignBody
    Returns
    NewsletterCampaign
    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/platform/newsletter/campaigns/{id}Requires platform:newsletter:read

    One campaign (staff) (K9)

    Returns
    NewsletterCampaign
    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/platform/newsletter/campaigns/{id}Requires platform:newsletter:author

    Update a campaign draft (staff) (K9)

    Edits a draft campaign. Only a draft is editable. Platform tenant only.

    Body
    NewsletterCampaignBody
    Returns
    NewsletterCampaign
    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/platform/newsletter/campaigns/{id}/approveRequires platform:newsletter:publish

    Approve a submitted campaign — the second person sends it (staff) (K9)

    The second half of the two-person send: a DIFFERENT staff member than the submitter approves, which sends the campaign now, or schedules it if its `schedule_at` is in the future. The submitter cannot approve their own — a 403 typed `system/dual-control`. Platform tenant only.

    Returns
    NewsletterCampaign
    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/platform/newsletter/campaigns/{id}/cancelRequires platform:newsletter:publish

    Cancel a campaign before it sends (staff) (K9)

    Returns
    NewsletterCampaign
    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/platform/newsletter/campaigns/{id}/reportRequires platform:newsletter:read

    A campaign report from the real outbox and suppression data (staff) (K9)

    Honest counts: queued/sent/failed from the campaign’s outbox rows, and bounced/complained from the marketing suppression list for the addresses this campaign reached. Opens and clicks are not reported — the outbox does not know them, and a fabricated open rate would be dishonest. Platform tenant only.

    Returns
    NewsletterCampaignReport
    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/newsletter/campaigns/{id}/submitRequires platform:newsletter:author

    Submit a campaign for sending (staff) (K9)

    The first half of the two-person send: records who submitted it. A DIFFERENT staff member must approve to send. Platform tenant only.

    Returns
    NewsletterCampaign
    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/platform/newsletter/campaigns/{id}/testRequires platform:newsletter:publish

    Send a test of a campaign to a staff address (staff) (K9)

    An honest real send of the rendered campaign to one staff address on the marketing stream. Platform tenant only.

    Body
    NewsletterTestSend
    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/platform/newsletter/listsRequires platform:newsletter:read

    Every newsletter list (staff) (K9)

    The mailing lists, by slug. Platform tenant only.

    Returns
    NewsletterListList
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/platform/newsletter/lists/{slug}Requires platform:newsletter:author

    Delete a newsletter list (staff) (K9)

    Removes the list. Subscribers keep their membership slug. Platform tenant only.

    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.
  • PUT/v1/platform/newsletter/lists/{slug}Requires platform:newsletter:author

    Create or update a newsletter list (staff) (K9)

    Creates or updates the list at the slug. Platform tenant only.

    Body
    NewsletterListBody
    Returns
    NewsletterList
    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/platform/newsletter/segmentsRequires platform:newsletter:read

    Every newsletter segment (staff) (K9)

    The named safe filters over lists. Optional `?list=` narrows to one list. Platform tenant only.

    Returns
    NewsletterSegmentList
    Parameters (2)
    • list · query — Narrow to segments of this list slug.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/platform/newsletter/segments/{slug}Requires platform:newsletter:author

    Delete a newsletter segment (staff) (K9)

    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.
  • PUT/v1/platform/newsletter/segments/{slug}Requires platform:newsletter:author

    Create or update a newsletter segment (staff) (K9)

    A segment is a named SAFE filter over a list — locale, joined-after date, and also-on-lists membership — not arbitrary code. Platform tenant only.

    Body
    NewsletterSegmentBody
    Returns
    NewsletterSegment
    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/platform/newsletter/subscribersRequires platform:newsletter:read

    Newsletter subscribers (staff) (K9)

    The subscriber list with states and hashes. Optional `?list=` and `?state=` filters. An ERASED subscriber shows no email — the plaintext was cleared and only the hash survives. Platform tenant only.

    Returns
    NewsletterSubscriberList
    Parameters (3)
    • list · query — Narrow to one list slug.
    • state · query — One of pending, confirmed, unsubscribed.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/newsletter/subscribers/{id}/consentRequires platform:newsletter:read

    One subscriber’s consent trail (staff) (K9)

    The append-only consent audit for a subscriber: when they opted in, confirmed, unsubscribed or were erased. After erasure the PII is redacted but the actions and times remain. Platform tenant only.

    Returns
    ConsentRecordList
    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/newsletter/subscribers/{id}/eraseRequires platform:newsletter:publish

    Erase a subscriber (staff) (K9)

    The right to be forgotten, erasure-safe: clears the plaintext email and the consent PII while keeping the email hash, the stable unsubscribe token hash, the suppression tombstone and the consent timeline. The address stays suppressed forever as a one-way token with no retained PII. Platform tenant only.

    Returns
    NewsletterSubscriber
    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.

notification 12

  • GET/v1/notificationsRequires platform:notification:read

    The in-app notification feed for this company

    Returns
    NotificationFeed
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/notifications/{id}/dismissRequires platform:notification:manage

    Dismiss one notification from the feed

    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/notifications/{id}/readRequires platform:notification:manage

    Mark one notification as read

    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/notifications/categoriesRequires platform:notification:read

    The notification categories a company can set a delivery preference for (K7)

    The preferenceable alert sources with a short label and description, so each console renders the Notifications page without hardcoding the taxonomy. The account category (sign-up verification) is excluded: it is never gated.

    Returns
    NotificationCategories
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/notifications/contactsRequires platform:notification:read

    Who receives this company’s emails, per kind

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/notifications/contactsRequires platform:notification:manage

    Set who receives this company’s emails

    Invoices and payment receipts go to `billing`, staff actions on the account to `security`. Nobody named means nothing is sent.

    Body
    NotificationContacts
    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/notifications/onboardingRequires platform:notification:read

    This company’s first-run onboarding checklist (L7)

    Each onboarding step with whether it is really done (its live store signal, never a hardcoded tick), a short label and the console path to do it at, plus `complete` when every step is done. The same signals the lifecycle email engine (L2) is driven by, shown for a screen.

    Returns
    OnboardingChecklist
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/notifications/outboxRequires platform:notification:read

    The emails sent to this company, newest first, and any that failed

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/notifications/preferencesRequires platform:notification:read

    This company’s mail preferences: the locale and per-category delivery (K5/K7)

    One locale per company, not per contact, plus the per-category delivery choice (K7). Every preferenceable category is returned filled with its resolved value — the stored choice or the instant default — so the console shows the real effective state. Defaults to en and instant when none is set, so an existing company is unchanged.

    Returns
    MailPreferences
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/notifications/preferencesRequires platform:notification:manage

    Set the locale and per-category delivery this company’s emails use (K5/K7)

    Both parts are optional, so a caller can set just the locale (en, de, fr, es, ar) or just the per-category delivery map (each of billing, security, budget, video, cloud, pipeline, agent set to instant, digest or off). An omitted part is left unchanged. The account category is never settable: a sign-up verification is always sent.

    Body
    MailPreferences
    Returns
    MailPreferences
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/notifications/signup-verificationRequires platform:notification:send_account

    Send a sign-up verification email (signup provisioner only)

    Queues the email that proves a signer owns their address (A5). The link carries the token and points at the marketing site’s verify page; the token is not stored anywhere but the message. Platform tenant only. Idempotent on the signup id and send number.

    Body
    SignupVerificationEmail
    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/notifications/suppressionsRequires platform:notification:read

    Suppressed addresses, so the billing page can flag bounced contacts (K4)

    The addresses the platform will not send to — bounced or complained — so a company can cross-reference its own billing, security and operations contacts and see which are not receiving mail. Deliberately only an address, a reason, a stream and a time: the suppression list is the platform’s own and is not tenant-scoped, so returning anything that could tie an address to another company would be a cross-tenant leak. The caller matches these against the contacts it already knows are its own.

    Returns
    SuppressedAddressList
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

observability 2

  • GET/v1/platform/observability/dashboardsRequires platform:observability:read

    The standard per-tenant dashboards

    The panel definitions a console renders. The same for every tenant; the data behind each panel is scoped to the caller when the panel’s query is run against `POST /v1/platform/observability/query`.

    Returns
    TenantDashboardList
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/observability/queryRequires platform:observability:read

    Run one dashboard query, scoped to your tenant

    Names a metric from the per-tenant inventory and, at most, filters and groups by a short allow-list of labels. The tenant is taken from your token and injected as `projectx_tenant="<you>"` at the query layer; a request that names the tenant label itself, in a matcher or a group-by, is refused rather than honoured. Process and edge metrics are not queryable here because they carry no tenant.

    Body
    MetricsQueryRequest
    Returns
    MetricsQueryResult
    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.

operation 12

  • GET/v1/offboarding/certificates/{id}Requires platform:operation:read

    The revocation certificate a finished sweep issued

    SHA-256 over a fixed field order, so a customer’s own tooling can recompute the digest rather than taking it on trust, and `audit_hash` points into the tenant’s own hash chain.

    Returns
    RevocationCertificate
    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operationsRequires platform:operation:list

    List long-running operations

    Parameters (5)
    • tenant · query — Whose operations to list. Defaults to your own.
    • kind · query — Operation kind, such as `vps.provision`.
    • state · query — pending, running, succeeded, failed, cancelled or compensating.
    • target · query — URN of the resource being operated on.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/operations/{id}Requires platform:operation:read

    Fetch one operation with its steps and progress

    Every step reports its own state, attempts and error, so a stuck provision can be read without opening the workflow engine.

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

    Approve an operation that is waiting on a human

    The requester cannot approve their own operation, so a gate asking for one approval genuinely needs two people. The last approval needed resumes the run from the step it stopped at; anything short of it records the approval and leaves the operation parked.

    Body
    ApprovalRequest
    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/operations/{id}/cancelRequires platform:operation:cancel

    Cancel an operation

    Stops before the next step rather than killing the step already in flight, so a half-created server is finished and then compensated rather than abandoned.

    Body
    CancelRequest
    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/operations/{id}/rejectionRequires platform:operation:approve

    Refuse an operation that is waiting on a human

    Cancels it. Nothing already done is undone — the steps before the gate are the ones that only read.

    Body
    RejectionRequest
    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/operations/{id}/retryRequires platform:operation:retry

    Run a failed operation again from where it stopped

    Continues rather than restarts: steps already done are left alone and only the failed and undone ones run again. A failed step keeps its idempotency key, so a provider that already half-completed it recognises the replay; an undone step gets a fresh one, because its side effect was deliberately reversed and the old key would be answered “already done” over a resource that no longer exists. Cancelled operations are refused — somebody stopped that on purpose.

    Body
    RetryRequest
    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/operations/{id}/signalRequires platform:operation:signal

    Send a named signal to a running operation

    Recorded on the operation and read by steps that look for it, at the next step boundary or by a step that polls. It does not interrupt a step already in flight — use cancel for that, which also stops between steps. Signalling a finished operation is refused rather than accepted quietly, because a message nobody will read is worse than an error.

    Body
    SignalRequest
    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/schedulesRequires platform:operation:list

    List operation schedules, each with how it is doing

    The health verdict is worked out on read rather than stored, so a schedule that is overdue because nothing is ticking says so. A stored column would keep reporting the last thing the ticker wrote, which on a dead ticker is “fine”.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/schedules/{name}Requires platform:operation:schedule

    Delete a schedule

    Parameters (3)
    • 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.
  • PUT/v1/schedules/{name}Requires platform:operation:schedule

    Create or replace a schedule

    Cron, event-driven or one-shot. `skip_if_running` is the difference between a nightly compaction that falls behind gracefully and one that piles up.

    Body
    Schedule
    Parameters (3)
    • 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.
  • PUT/v1/schedules/{name}/enabledRequires platform:operation:schedule

    Pause or resume a schedule without rewriting it

    Apart from the full replace, because pausing is not editing: an operator stopping a misbehaving nightly job should not have to retype its cron expression, target and input correctly first. Resuming does not backfill the runs missed while it was off.

    Body
    ScheduleEnabledRequest
    Parameters (3)
    • 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.

payment 8

  • GET/v1/paymentsRequires platform:payment:read

    List payments, newest first

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/paymentsRequires platform:payment:charge

    Charge a payment, optionally against an invoice

    The payment is recorded before the processor is called. A charge under Strong Customer Authentication may come back `requires_action`, which is a customer with one more tap to make, not a failure.

    Body
    ChargePayment
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/payments/{id}/authenticateRequires platform:payment:charge

    Complete an SCA challenge and settle the payment

    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/payments/{id}/credit-top-upRequires platform:payment:charge

    Credit the prepaid balance for a settled top-up payment (B10)

    The second half of a card or SEPA top-up whose charge parked for Strong Customer Authentication or settled asynchronously: once the payment has settled, this credits the prepaid balance for its amount, once (keyed on the payment, so a redelivered webhook tops up once). Refused while the payment has not settled.

    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/payments/{id}/retryRequires platform:payment:charge

    Retry a failed payment from where it stopped

    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/prepaidRequires platform:payment:read

    The prepaid balance and its ledger

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/prepaid/paid-top-upsRequires platform:payment:charge

    Top up the prepaid balance by charging a card or SEPA debit (B10)

    Money actually moves: the stored method (or the one named) is charged through the payment gateway, and the balance is credited only when the charge settles. A card under Strong Customer Authentication comes back `requires_action` with the payment to finish; a SEPA debit settles later; either way the balance is untouched until the money is really there. Settle it afterwards with `POST /v1/payments/:id/authenticate` and the balance is credited once.

    Body
    PaidTopUp
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/prepaid/top-upsRequires platform:payment:charge

    Add to the prepaid balance

    A positive ledger entry. The balance is the sum of the ledger, never a field, so the history and the balance cannot disagree.

    Body
    PrepaidTopUp
    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.

payment_method 3

  • GET/v1/payment-methodsRequires platform:payment_method:read

    List stored payment methods

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/payment-methodsRequires platform:payment_method:write

    Store a payment method

    The token is the processor’s reference, never a card number — a token that looks like a PAN is refused, because a card number arriving here is a caller about to store one.

    Body
    AddPaymentMethod
    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/payment-methods/{id}Requires platform:payment_method:delete

    Remove a payment method

    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.

plan 3

  • POST/v1/plansRequires platform:plan:manage

    Create a plan

    A plan is never edited: the price a company agreed to is a fact. A new price is a new plan, and the old one is retired.

    Body
    CreatePlan
    Parameters (2)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
    • Idempotency-Key · header — Makes a retry safe. A replay of the same key and body returns the stored response with Idempotency-Replayed: true; the same key with a different body is a 409.
  • POST/v1/plans/{id}/retireRequires platform:plan:manage

    Retire a plan

    No new subscriptions. Companies already on it stay on it, at the price they agreed — unless `move_to` names a plan, in which case each subscriber is moved to it at the start of the next billing period. The month they are in is billed under the plan they agreed to.

    Body
    RetirePlan
    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/plans/allRequires platform:plan:read

    Every plan, retired ones included (staff)

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

price_book 2

  • GET/v1/price-bookRequires platform:price_book:read

    Read the tenant’s price book

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/price-bookRequires platform:price_book:write

    Publish a price book

    Tiered prices, an optional commitment discount and an optional reseller markup. Infrastructure meters on customer-owned substrates carry no markup, and the rating engine enforces that rather than trusting the book.

    Body
    PriceBook
    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.

public 9

  • GET/v1/plans

    The plans on sale

    Public, like the brand: the pricing page and the signup form read it before anybody has signed in. Active plans only, cheapest first. A retired plan is still billed to the companies on it but is not offered (`PLT-SUB-001`).

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/blog

    The published blog posts (K8)

    Public, like the plans: the marketing site reads it to render `/blog` and the feeds. Published posts only, newest first, each with a rendered-safe `html` field so no reader renders markdown itself. Optional `?tag=` filter. A scheduled post is absent until its time passes.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/blog/{slug}

    One published blog post (K8)

    Public. The full post with its rendered-safe `html`. A draft, submitted, scheduled-not-yet-due or archived post is a 404 here — the same "no such thing" a reader gets for a slug that never existed, leaking nothing about posts that are not live.

    Parameters (2)
    • slug · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/blog/tags

    The distinct tags across published posts (K8)

    Public. The facet list the marketing site renders as filter links. Sorted. Tags of drafts and scheduled posts are not included.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/branding

    The brand this deployment renders under

    Public, cacheable, and the same for every caller. A product name and a logo URL are not secrets, and treating them as though they were would mean the sign-in page could not use them. Answers even when no brand has ever been set, with the compiled-in default — a console must never fail to render chrome over a cosmetic setting.

    Returns
    Brand
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/contact/challenge

    A proof-of-work challenge for the contact form (H7)

    Public. Returns `{ challenge, difficulty }`. The contact form grinds a nonce whose `sha256(challenge:nonce)` has `difficulty` leading zero bits, and presents `{ challenge, nonce }` to the submit POST. Single-use with a short TTL; not cacheable.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/platform/newsletter/challenge

    A proof-of-work challenge for newsletter sign-up (K9)

    Public. Returns `{ challenge, difficulty }`. The sign-up form grinds a nonce whose `sha256(challenge:nonce)` has `difficulty` leading zero bits, and presents `{ challenge, nonce }` to the sign-up POST. Single-use with a short TTL; not cacheable.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/public/credits

    What a credit costs, the smallest deposit, and the first-deposit bonus

    Public, cacheable, the same for every caller. `credit_price_minor` is the list price of one credit per currency (from the default rate card, never a private one). `minimum_deposit` is the smallest deposit, in credits and in each currency. `deposit_bonus` is the first-deposit bonus: the promotional credits a company earns once on its first settled deposit of at least `minimum_credits`, what they are worth at list, and the days before they lapse.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/public/pricing

    Public compute and usage-product prices from the default credit card

    Public, cacheable, the same for every caller. `products` contains compute products with rates by size, plan, cloud and region. `usage_products` contains Lifecycle, Verify, Workplace, Video Search & Alerts, Ask, Workflows and Agents with credits and list prices per published unit — a governed active-human month, managed-device month, completed verification, camera-month, 1,000 questions, 1,000 workflow runs or agent run — and the `unit_multiplier` that converts it to the meter the invoice rates. Both are projected from the platform default rate card used by billing — list prices only, never a private card. A product the card does not price is absent rather than shown at zero; an unset compute dimension means any plan, cloud or region.

    Returns
    ProductPriceList
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

rate_card 7

  • GET/v1/credit-rate-cardsRequires platform:rate_card:read

    Every credit rate card: the default and each private one (staff)

    Platform tenant only. The built-in default is listed until staff publish one.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/credit-rate-cards/{id}Requires platform:rate_card:manage

    Publish a credit rate card (staff)

    `default` is the platform’s card, which every company without its own is rated by and the pricing page publishes. Any other id is a company’s tenant key and makes that company’s private card (B6). Replaced whole. Platform tenant only.

    Body
    PutCreditRateCard
    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/credit-rate-cards/{id}/proposalsRequires platform:rate_card:read

    The change proposals for one credit rate card (staff)

    Newest first, every state. Platform tenant only.

    Parameters (2)
    • id · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/credit-rate-cards/{id}/proposalsRequires platform:rate_card:manage

    Propose a credit rate card change for approval (staff)

    Four-eyes publishing (N1): the proposed card is the whole card (rates, including the optional plan/cloud/region dimensions, and the credit price), validated now and held `pending_approval` until a different person approves it. `default` targets the platform card; any other id a company’s private card. Platform tenant only.

    Body
    ProposeCreditRateCard
    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/credit-rate-cards/proposalsRequires platform:rate_card:read

    Every credit-rate-card change proposal, for the review queue (staff)

    Newest first. `pending=true` narrows to those still awaiting a second person — the operator review screen. Platform tenant only.

    Parameters (2)
    • pending · query — Set to `true` to return only proposals still awaiting approval.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/credit-rate-cards/proposals/{proposalId}/approveRequires platform:rate_card:manage

    Approve a credit rate card change proposal (staff)

    The second person agrees (N1): the proposed card is published as a new effective-dated version. Refused for the proposer — a 403 typed `system/dual-control`, the four-eyes rule. Platform tenant only.

    Parameters (3)
    • proposalId · 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/credit-rate-cards/proposals/{proposalId}/rejectRequires platform:rate_card:manage

    Reject a credit rate card change proposal (staff)

    The second person declines (N1): the proposal is marked `rejected` and nothing is published. Refused for the proposer, like approval. Platform tenant only.

    Body
    RejectRateCard
    Parameters (3)
    • proposalId · 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.

referral 3

  • POST/v1/platform/referrals/attributeRequires platform:referral:attribute

    Attribute a referral to a new company that signed up (provisioner) (L3)

    The seam between the cloud sign-up flow (not modified by L3) and the referral programme. The provisioner — or staff — calls this with the referral `code` and the new company’s `tenant`; the marketing `/signup?ref=<code>` carries the code through to this call when that integration lands. Platform tenant only. Deliberately forgiving so a referral never fails a sign-up: a bad code, a repeat (one referral per referred company) or a company that already has activity is a no-op, and only a self-referral is refused. The reward is NOT paid here — it is paid later, only when the referred company reaches its first paid invoice.

    Body
    AttributeReferral
    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/referralsRequires platform:referral:read

    The referrals this company made, with states and rewards (L3)

    Only the caller’s own referrals, and only the minimal facts it legitimately knows about each: the referred company key, the state (pending, qualified, rewarded or void), the timestamps, and the credits earned once rewarded. The referred company’s own billing details are never exposed here.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/referrals/codeRequires platform:referral:read

    This company’s referral code, created on first ask (L3)

    The short, shareable code a company puts in front of a prospect. Get-or-create: the first call mints a stable code and every later call returns the same one. The caller builds the share link — `${marketing}/signup?ref=<code>` — from the code; the service owns the code, not the URL. When the referred company becomes a paying customer, both earn promotional credits (non-transferable and lapsing, by the credit ledger’s rules).

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

sla_credit 5

  • GET/v1/platform/sla-creditsRequires platform:sla_credit:review

    SLA service-credit claims awaiting review, across every company (staff) (L9)

    Platform tenant only. The review queue: every company’s claims still in the submitted state, oldest first.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/sla-credits/{id}/approveRequires platform:sla_credit:review

    Approve an SLA claim and grant the promotional credit (staff) (L9)

    Platform tenant only. The approver determines the affected service’s fees for the month — read from the month’s invoice when one exists, or supplied as `month_fees_minor`. The credit is `credit_pct%` of that basis, capped at it, granted as a promotional credit: non-transferable, lapsing and not a refund, and granted only here, never automatically. Approving twice grants once.

    Body
    ApproveSlaCredit
    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/platform/sla-credits/{id}/rejectRequires platform:sla_credit:review

    Reject an SLA service-credit claim (staff) (L9)

    Platform tenant only. Ends the claim with a reason. Nothing is granted. Only a claim awaiting review.

    Body
    RejectSlaCredit
    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/sla-creditsRequires platform:sla_credit:read

    This company’s SLA service-credit claims (L9)

    Every claim this company filed, newest first, in each state: submitted, approved (with the promotional credit granted) or rejected (with the reason).

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/sla-creditsRequires platform:sla_credit:claim

    File an SLA service-credit claim for a month below target (L9)

    The service credit is claim-based, not automatic: filing a claim does not grant anything — staff review it, and only on approval is a promotional credit granted (capped at the affected service’s fees for the month). One claim per service per month. A month that met the 99.9% target earns nothing. The credit band follows the /sla page: below 99.9% to 99.0% is 10%, below 99.0% to 95.0% is 25%, below 95.0% is 50%.

    Body
    ClaimSlaCredit
    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.

subscription 6

  • GET/v1/entitlementsRequires platform:subscription:read

    This company’s plan entitlements

    The machine-enforced capability set the company’s current plan grants (N2), resolved live from the plan — an upgrade takes effect at once. A company with no active plan, or a plan that grants none, gets an empty set. These are the Enterprise-only surfaces: customer-managed keys, private networking, compliance profile, extended audit retention, and an SLA tier.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/outstandingRequires platform:subscription:list

    What every company owes, read from invoices (staff) (B13)

    The outstanding figure for the analytics dashboard, read straight from invoices rather than from subscriptions, so a company billed by its price book alone — invoices but no plan — is counted too. Grouped by company and currency, with a per-currency total. Platform tenant only.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/subscribersRequires platform:subscription:list

    Every company’s plan and what it owes (staff)

    For the super admin’s Customers grid (`PLT-SUB-004`): plan, price, since when, and the outstanding balance on unpaid invoices, per currency.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • DELETE/v1/subscriptionRequires platform:subscription:manage

    Cancel this company’s plan

    This month is billed up to today; nothing after.

    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/subscriptionRequires platform:subscription:read

    This company’s plan, and the plans it held before

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • PUT/v1/subscriptionRequires platform:subscription:manage

    Choose or change this company’s plan

    Takes effect now. This month’s invoice bills each plan held for the days it was held.

    Body
    ChoosePlan
    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.

usage 6

  • GET/v1/catalog/entries/{urn}/costRequires platform:usage:read

    What this resource has cost so far this period

    Rated at read time against the current price book, so a corrected price corrects the answer. Meters the book does not price are named rather than counted as free.

    Parameters (2)
    • urn · path · required — The resource URN, used verbatim.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/invoices/{number}/showbackRequires platform:usage:read

    Attribute an invoice to the teams that ran up the bill

    Parameters (3)
    • number · path · required
    • by · query — `project` or `workspace`. Defaults to project.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/usageRequires platform:usage:read

    Read rolled-up usage records

    Parameters (8)
    • meter · query — One meter from the catalog.
    • period · query — `hourly`, `daily` or `monthly`.
    • workspace · query — Workspace URN.
    • project · query — Project URN.
    • resource · query — URN of the metered resource.
    • from · query — Inclusive RFC 3339 lower bound.
    • to · query — Exclusive RFC 3339 upper bound.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/usage/{tenant}/eventsRequires platform:usage:read_any

    One company’s raw meter events, for a pillar or staff

    The unrated meter stream a pillar rates its own cost view from (`CLD-FIN-001`): the same events `POST /v1/meters/events` accepted, read back by the service that rated them. Platform tenant only — the same posture as `/v1/credit-standings/:tenant`, because the pillar holds nothing in the customer tenant.

    Parameters (2)
    • tenant · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/usage/exportRequires platform:usage:read

    Export rolled-up usage as CSV or Parquet

    The same records `GET /v1/usage` returns, as a file finance tooling reads directly. Both formats carry the same columns in the same order; Parquet is the one a columnar tool loads without a dialect negotiation.

    Parameters (9)
    • format · query — `csv` or `parquet`. Defaults to csv.
    • meter · query — One meter from the catalog.
    • period · query — `hourly`, `daily` or `monthly`.
    • workspace · query — Workspace URN.
    • project · query — Project URN.
    • resource · query — URN of the metered resource.
    • from · query — Inclusive RFC 3339 lower bound.
    • to · query — Exclusive RFC 3339 upper bound.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/usage/tenantsRequires platform:usage:read_any

    Every company with usage, for a fleet-wide sweep

    The enumeration a pillar sweep needs and nothing tenant-keyed can answer (`PLT-SCH-007`): the spend-anomaly sweep visits each company with usage, so the list comes from the metering store the usage lives in. Platform tenant only.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.

user 1

  • POST/v1/offboardingRequires iam:user:lifecycle

    Offboard a departing principal

    Enumerates first, then stops for one human approval, then revokes in dependency order and issues a sealed revocation certificate. Nothing is destroyed: what a successor does not inherit is tagged `orphaned` and given the requester as interim steward. Returns the operation immediately — poll it, and approve it at `/v1/operations/{id}/approve`.

    Body
    OffboardRequest
    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.

webhook 13

  • POST/v1/platform/contact

    Public contact-form submission (H7)

    Anonymous POST. Authenticity is a solved proof-of-work (not a bearer token): the handler verifies and burns a single-use challenge issued by `GET /v1/platform/contact/challenge` before anything is queued. Validates the message and queues an email to the brand’s support address on the transactional stream, with the sender’s address as `Reply-To`. Names no tenant and carries no customer data — it is a stranger’s message to our inbox.

    Body
    ContactRequest
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/mail/webhooks/{provider}

    A mail provider’s delivery notification (K4)

    Where a configured mail provider POSTs delivery, bounce, complaint and open events. Unauthenticated: the call’s authenticity is an HMAC signature over the exact body, verified against the provider’s webhook signing secret in the vault, not a bearer token. A bounced or complained event suppresses the recipient on the event’s stream; delivered and opened are informational. A call whose signature does not verify is refused and records nothing.

    Body
    MailProviderWebhook
    Parameters (2)
    • provider · path · required
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/newsletter/confirm

    Public newsletter confirm — double opt-in step 2 (K9)

    Anonymous POST. Authenticity is the single-use confirm TOKEN from the email, compared in constant time against the stored hash (not a bearer token). A POST, not a GET side effect, because a mail scanner opens every link — the confirm page is a button the human clicks. Flips the subscriber to confirmed and records a confirm consent.

    Body
    NewsletterConfirm
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/newsletter/preferences

    Public preference centre read/update (K9)

    Anonymous POST. Authenticity is the stable preference TOKEN (constant-time compared against the stored hash) — no login needed. With no `lists` field it READS the current lists and locale; with a `lists` field it UPDATES them (clearing every list is an unsubscribe). Returns the subscriber’s lists and locale.

    Body
    NewsletterPreferences
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/newsletter/signup

    Public newsletter sign-up — double opt-in step 1 (K9)

    Anonymous POST. Authenticity is a solved proof-of-work (not a bearer token): the handler verifies and burns a single-use challenge issued by `GET /v1/platform/newsletter/challenge` before anything is created. Creates or finds a pending subscriber, records an opt-in consent, and queues a CONFIRMATION email on the transactional stream. The confirm link in that email is the only place the confirm token exists; a bogus address simply never clicks it.

    Body
    NewsletterSignup
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/platform/newsletter/unsubscribe

    Public one-click unsubscribe (K9)

    Anonymous POST. Authenticity is the stable unsubscribe TOKEN (constant-time compared against the stored hash). The RFC 8058 one-click target carried in every campaign’s `List-Unsubscribe` header. A POST, not a GET side effect. Drops one list (`list`) or all; when the last list goes it writes a marketing suppression and an unsubscribe consent so the address stays off even if re-added.

    Body
    NewsletterUnsubscribe
    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • GET/v1/webhooksRequires platform:webhook:read

    List webhook endpoints

    Secrets are never included. They are shown once, at creation and at rotation.

    Parameters (1)
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/webhooksRequires platform:webhook:write

    Create a webhook endpoint

    Returns the signing secret exactly once. Store it on receipt; recovering from a lost secret means a rotation, not a lookup.

    Body
    CreateWebhookRequest
    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/webhooks/{name}Requires platform:webhook:delete

    Delete a webhook endpoint

    Parameters (3)
    • 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.
  • PATCH/v1/webhooks/{name}Requires platform:webhook:write

    Change an endpoint’s URL, subscriptions or enabled state

    Re-enabling an endpoint that was auto-disabled clears its failure count, which is how an operator says the far end is fixed.

    Body
    UpdateWebhookRequest
    Parameters (3)
    • 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.
  • POST/v1/webhooks/{name}/rotateRequires platform:webhook:write

    Rotate an endpoint’s signing secret

    The old secret keeps verifying for an overlap window, so a receiver can pick up the new one without dropping deliveries in between.

    Body
    RotateSecretRequest
    Parameters (3)
    • 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.
  • GET/v1/webhooks/deliveriesRequires platform:webhook:read

    List recent delivery attempts

    Parameters (3)
    • endpoint · query — Endpoint URN, to narrow to one subscription.
    • limit · query — How many to return. Defaults to 50.
    • X-Request-Id · header — Echoed on the response and recorded on the audit event.
  • POST/v1/webhooks/deliveries/{id}/replayRequires platform:webhook:replay

    Queue a failed delivery for another attempt

    Replays the original envelope, so the receiver sees the same event id and can deduplicate.

    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.
ProjectX Control Plane · API reference · ProjectX