Adds three product surfaces to the reference — cPanel hosting, Mailspace mail
hosting (buying one and managing everything inside it), and a WordPress site's
transactional email — plus backup exports, and corrects reference content that
shipped in 2026.8.0.
API reference verified against CloudPress platform release 2026.08.01.
This release documents platform release 2026.08.01, which is not yet live. The
cPanel, Mailspace and transactional-email endpoints, the three new OAuth scopes, and
themissing_accountanddomain_availability_unknownerror codes all ship with it.
Everything else below is already in production.Nothing was published between 2026.8.0 and this release, so if you are upgrading, you
are getting all of the below in one step.
Added
- cPanel hosting (
reference/endpoints-cpanel.md, new). Account list/show,
ordering, package resizes, cancellation, immediate purge, control-panel
password changes, one-time control-panel login sessions, and per-account domain
management (aliases, subdomains, add-on domains) with the per-kind usage and
limit counters. Includes the availability gate (cpanel_not_enabled), the
full error-code table per endpoint, the 500-account listing ceiling, and the
role each operation requires — evaluated on the owning account, not on
X-Auth-Account. - Mailspace mail hosting (
reference/endpoints-orders.md). Purchase, resize,
soft-delete, the domain-ownership TXT verification block, and the hold
semantics that edit access does not override. - Mailspace mail management — three new reference files, ~61 endpoints, all on the
mailspace:read/mailspace:writescopes above:reference/endpoints-mailboxes.md— mailboxes (keyed by guid, not address),
app passwords, mail rules (includingtoggle,moveandadopt), vacation
responses, purged-mailbox recovery, and archived deleted mail. Covers the
irreversibleforce_deleteand its409 not_pending_deletionprecondition, and the
downloadroute, which returns rawmessage/rfc822rather than JSON.reference/endpoints-mail-routing.md— aliases (keyed by address), groups and
mailing lists (keyed by the mail server's principal id), masked emails, and the
delivery-logs endpoint.GET /groupshas two503s and the code says which read
failed:groups_unavailablefor the group list,group_members_unavailablefor the
member tally alone. Theqfilter matches the address and the description on both
groups and mailing lists — the same two fields, with the same predicate. The logs endpoint returnsincoming,outgoing,queueand
issuesunder separate keys because they have different upstream availability —
documented so that "trace data not licensed" stays distinguishable from "no mail
problems".reference/endpoints-mailspace.md— mail domains and their required DNS records,
both ownership-verification surfaces (the primary domain's runs before
provisioning), and the permanent purge.PATCH .../domains/:nametreats
descriptionas three-way: omit the key to leave it untouched, send""to clear
it, send a value to set it. DNS record values are returned live in the
response and the file says to publish them verbatim rather than hardcoding them.
- Transactional site email (
reference/endpoints-sites.md) — overview, sender
settings, suspension, sender-DNS check, send logs, and mail metrics at
/api/sites/:site_id/mail. Two behaviours that the HTTP verb actively misleads on:
the suspension endpoint is aDELETEthat lifts a hold, and the overview mounts at
/mailwith no/overviewsegment. - Backup exports (
reference/endpoints-sites.md). Request an archive export
and poll for the short-lived presigned download URL, including why both the
request and the status read are gated assites:write. - Three OAuth scopes:
mailspace:read,mailspace:write, andcpanel:read.
Documented alongside the fact that there is deliberately nocpanel:write—
every cPanel write is OAuth-blocked and needs a session or API-key credential.
Two consequences are called out explicitly, because neither is obvious from the scope
name:- They spend money.
mailspace:writeandsites:writeeach reach an endpoint that
builds a cart and charges the account off-session, so an OAuth token holding either
can spend money. This does not generalise from the absence of abilling:write. mailspace:*reaches mail itself, not just subscription metadata.
mailspace:readreads delivery logs and downloads raw archived messages;
mailspace:writereaches mailbox force-delete and the immediate purge of a
soft-deleted mailspace. There is no narrower mail scope to request instead.
- They spend money.
- The gate chain for everything nested under
/api/mailspace/:id— the order, the
code for each (stalwart_unavailable503,not_authorized403,mailspace_suspended
403,pending_delete403,not_provisioned409), and which are decided on the HTTP
verb rather than the action name.not_authorizedandpending_deleteare verb-gated,
so reads stay available on a soft-deleted mailspace;mailspace_suspendedis not,
and refuses reads too despite a message saying "cannot be modified". Two deliberate
exceptions: purge does not applypending_delete(soft-deleted is its precondition) and
primary-domain verification does not applynot_provisioned. - The mailspace read-failure convention, documented as a cross-cutting rule. Every
index inside a mailspace reads the mail server live, and a read that could not be
performed answers503under a per-resource code —mailboxes_unavailable,
domains_unavailable,aliases_unavailable,groups_unavailable,
mailing_lists_unavailable,archived_items_unavailable,
purged_mailboxes_unavailable— rather than a200carrying an empty collection. The
consequence is the reason it is inSKILL.mdrather than only per endpoint: an empty
array on those endpoints means the mail server was asked, so a client may reconcile its
own state against it. It is honesty about the read, not completeness — the 500-row caps
still truncate silently, andpurged_mailboxesapplies its cap server-wide before tenant
filtering, so an empty list there is still not proof the mail is gone. The exceptions are
enumerated rather than left to inference — mail rules answer
422 mail_rules_unavailable, and the app-password list, masked emails, delivery logs and
the by-id group / mailing-list lookups are still tolerant. 503on a mailspace write answers one of two opposite questions, and the skill
now says which per code.restore_unavailable(purged-mailbox restore) and
archived_item_lookup_unavailablemean nothing was attempted.restore_unconfirmed
anddelete_unconfirmed(archived mail) andaliases_unavailableon an alias write
mean the request went out and its fate is unknown — re-read before retrying, and
especially so fordelete_unconfirmed, where the erase is irreversible.
delete_unavailableon mailbox force-delete is a third case: the mailbox is gone and
what could not be established is whether its mail is still recoverable. A422is the
only answer that means the mail server replied and refused.- New codes and async shapes on the mail surface:
400 invalid_days(a non-numeric
dayson mail metrics),409 already_provisioned(a verification retry on a mailspace
already set up),409 not_recoverablecovering the terminal "the mail server has
already erased this account" branch of a purged-mailbox restore (so422 restore_failed
means only that the server refused, and is retryable),503
archived_item_lookup_unavailable,restore_unconfirmedanddelete_unconfirmedon
the archived-mail by-id routes, and two202shapes: the primary-domain verification
returns the verification block (poll the same path untilstateis"provisioned"),
and the site mail DNS check returns{"status":"queued"}with nothing to poll. Also:
download_unavailableon an archived-mail download carries two statuses —404
when the mail server answered that the message is gone (terminal),503for any other
read failure (retriable) — andX-Auth-Accountis not required on the nested
mailspace routes even thoughPOST /api/mailspacerequires it. list_site_tasksMCP tool (66 tools total), with the pagination difference
from its REST counterpart called out.- cPanel billing webhooks (
reference/webhooks.md). A third outbound payload
block,cpanel_account_link, withcreated/resized/owner_change/
deleted. Becauseactionstrings are reused across resource kinds, the file
now says explicitly: route on the resource block, never onactionalone.
Changed
- Task
labelsare redacted andperformed_byis masked. Keys beginning
callback_are stripped, so a callback URL and itsAuthorizationvalue can
never be read back from a task. Platform automation reports
{id: null, name: "System"}and CloudPress staff{id: null, name: "Support"}
— a nullperformed_by.idis meaningful, not missing data. Applies to the REST
endpoints and the MCP tool alike. POST /api/sites/:site_id/domainsdocumented as "connect a domain." It
attaches the domain as the site's primary only when the site has none, and as an
alias otherwise. Adds thereplace_recordsparameter and the four error codes
the endpoint now returns (domain_blank,conflicts_found— which carries a
conflictsarray —hostname_in_use,invalid_domain).- DNS writes state their role gates. Zone update requires edit access and
zone delete requires destroy access (both403forbidden), as do record
create, update and delete. 400 missing_accountaccompanies theMissing X-Auth-Accounterror body on
the endpoints that enforce the header — the list is enumerated inSKILL.md,
andPOST /api/dns_zonesis a deliberate exception that returns the same
message with nocodekey. Per-site task404s carrycode: "unknown_task";
the global task endpoints return an empty404body instead.429no longer always means an empty body. 2026.8.0 documented the rate-limit
response as empty; that is true of the global 600-per-10-minutes limit, but two
per-endpoint DNS-check limiters (one run per 5 minutes) return
{"errors":[...],"code":"rate_limited"}— the mailspace DNS check per domain, and the
site mail DNS check per site, which shares its limiter with the control panel.
Fixed
- Corrections to reference content that shipped in 2026.8.0. Every page was
re-derived against the platform source; the following were wrong before and are
worth checking if you built against them:POST /api/sites/:site_id/domains/request_certificatenever had awildcard
parameter, and the certificate status response has nowildcardfield.
Wildcard certificates are not supported by that flow.- The domain availability check returns the registration price as
price,
notcreate_price. - The CDN metrics response keys the cache hit rate as
CacheHitRate, not
CacheHitRatio. Its bandwidth figures are raw bytes — the control panel's
KB conversion and hit-rate rounding are not applied to the API response. - Shield activation reports a missing pull zone as
shield_not_active;
cdn_not_activenever appears anywhere in the Shield path. POST /api/sites/:site_id/metrics/*andPOST /api/sites/:site_id/metrics/cdn
require site edit permission in addition tosites:read.- The rate limit is keyed per client IP and counted per resource group,
not per credential across all of/api. - Example values that did not correspond to anything real have been replaced
throughout — nameserver hostnames (never hardcode them; read the pair from the
response), Mailspace package keys, location and plan identifiers, and example
domains. A site'spackagefield carries the product display name; the
short name is what requests take. 202responses do not uniformly carry a task reference. The complete set
of202shapes is now enumerated inSKILL.md.- Index endpoints do not uniformly paginate; the five that do are named.
422 domain_availability_unknownon domain orders. A failed availability
check is no longer reported asdomain_unavailable. The distinction matters:
one is a claim that the name is taken, the other is no claim at all and should
be retried rather than shown to a customer as unavailable.
Install for Claude Code with /plugin marketplace add cloud-press/skills,
or for Cursor, Codex, opencode and other agents with npx @cloud-press/skills.
The attached zip is for uploading the skill to claude.ai or Claude Desktop.