Schemas
AcceptInviteRequest
tokenThe token from the invitation link.
AcceptInviteResponse
accountIdThe account they are now a member of.
accountNameWhat it calls itself, or null when nobody has named it.
requiresTwoFactorWhether the account joined requires two-factor, so the page can say so before the gate does (IMPLEMENTATION-PLAN §5.3.6).
roleWhat they may do there.
AccountLinkResponse
emailThe address the link is about: the account's for a confirmation or a reset, the new one for a change of address.
kindWhich kind of link it is — verify, reset or change — so the page
says what its button will do.
AccountResponse
accountIdIts ULID.
kindWhether it belongs to one person or is shared.
nameWhat it calls itself, or null when nobody has named it.
AccountSecurityResponse
requireTwoFactorAtSince when two-factor is required, or null while it is not.
AccountSummary
accountIdWhat the account header carries to act on it.
kindPersonal or Team, which is what the switcher labels the entry with.
nameWhat it is called, or null for a personal account nobody has named.
roleWhat the caller may do there. The same string /me reports for the current one.
stoppedWhether the account has been stopped, directly or through one of its owners.
AccountTokenSummary
emailWhose it is.
idULID of the token, which is what an owner revokes it by. A handle, not a credential.
lastUsedAtWhen a request last authenticated with it, or null if never.
nameWhat they called it, which is what makes a list of them readable.
revokedWhether it has been revoked, as a flag rather than a date.
AccountsResponse
Every account the caller may act on, oldest membership first. Never empty for a signed-in person: signing in creates an account for them, and they are its owner.
AddSiteDomainRequest
alreadyServingWhether a site is already answering on this hostname, which is what decides how many records the customer is asked for.
False, or absent, takes the one-record path: the certificate provider proves ownership from the CNAME and answers the challenge from the edge, at the cost of a few minutes where the hostname has no certificate. True takes the older path — two TXT records first, certificate issued before the CNAME moves, no gap — which is worth its extra steps only to somebody with traffic to lose.
Asked rather than guessed because the answer is not visible from here: a hostname that resolves somewhere today may be a live business or a parked page, and the two want opposite things.
hostnameThe hostname to serve the site on, as the customer typed it. Normalized and validated on the server; what is stored is never this string directly (invariant I4).
AddSiteUpstreamRequest
Headers to attach to every call, values in plain text — sealed on arrival.
methodsMethods visitors may send; GET only when left out.
originhttps://host the site's _redirects sends calls to.
AddSiteViewersRequest
emailsThe addresses to add, as typed. Each is trimmed and lower-cased before it is stored; repeats collapse.
notifyWhether to mail each address added, defaulting to yes. Undo sends false: putting back somebody just removed should not mail them twice.
roleWhat every address added may do: View (the default) or Comment, in any case. Comment
is refused on a plan without comments. Addresses already listed keep the role they have.
AddSiteViewersResponse
addedThe addresses newly put on the list, as stored.
alreadyListedThe addresses sent that were on the list already, left as they were.
total^-?(?:0|[1-9]\d*)$ · requiredHow many people the list now holds, the owner included.
ApproveCliDeviceRequest
approvedTrue to hand the command line a token, false to refuse it.
userCodeThe short code as typed, in any case and with or without the dash.
ApproveCliDeviceResponse
approvedWhat was decided, echoed so a page rendering the result cannot disagree with the server.
clientNameWhat the command line calls itself, so the page can name it in the outcome.
AuthConfigResponse
googleClientIdOAuth 2.0 client id, safe to embed in client-side code.
passwordMinimumLength^-?(?:0|[1-9]\d*)$ · requiredFewest characters a password may have, so the page's rule list says the server's number.
turnstileSiteKeyKey the sign-up form renders its Turnstile widget with, or null when this deployment has none — in which case sign-up with a password is unavailable and the page should offer Google alone.
AuthorizeCliRequest
challengeUnpadded base64url SHA-256 of the verifier the command line kept.
clientNameWhat the command line calls itself; becomes the token's name.
callbackA named server-side callback instead of a port — mcp for the remote MCP server. Never a URL.
port^-?(?:0|[1-9]\d*)$The loopback port the command line is listening on. Exactly one of this and Callback.
AuthorizeCliResponse
codeThe one-time code. Returned exactly once and recoverable nowhere.
expiresAtWhen the code stops being exchangeable.
redirectUriWhere the consent page should send the browser, code appended as a query.
BatchFile
pathNormalized path, which the client uses to find the bytes and to name a failure.
sha256Digest, which is also how the layout line and the object's key are built.
BillingActionResponse
acceptedAlways true; the provider took the request.
BlockSiteCommenterRequest
commentIdA comment the person wrote on the site.
removeCommentsWhether to delete every comment they wrote on the site as well.
BlockSiteCommenterResponse
commentsRemoved^-?(?:0|[1-9]\d*)$ · requiredHow many of their comments were deleted now.
userIdThe person, as the Blocked list names them.
CancelDeletionRequest
tokenThe token the mailed link carried.
ChallengeResponse
emailWhose sign-in is waiting, so somebody on a shared computer can see it is not theirs.
expiresAtWhen the step closes.
ChallengeResult
returnToWhere the sign-in was going, for a Google sign-in, whose destination the server carried; null for the other ways in, whose page kept its own.
ChangePasswordRequest
currentPasswordThe password the account uses now.
newPasswordThe password to replace it with.
ChangePlanRequestBody
intervalBilling interval, month or year.
planIdId of the plan to move onto.
timingnow, or absent, which means the same thing: the change is applied immediately and the
difference is settled against the unused remainder of the current period. Kept in the contract only
so that period_end — which this route offered until the provider was found to have no way of
deferring anything — can be refused by name instead of being read as now and charging a
customer who was told nothing would be charged.
ChangeRoleRequest
roleThe role to give them: Owner or Member.
ChangeSeatsRequestBody
seats^-?(?:0|[1-9]\d*)$ · requiredHow many seats to be billed for from now on — the total, not a difference. A delta would make the request depend on what the client last read, so two owners pressing "add a seat" at once would buy two seats each.
ChangeSiteSubdomainRequest
subdomainThe new subdomain, as typed. Normalised the way a new site's is.
ChangeSiteViewerRoleRequest
roleThe role to give: View or Comment, in any case.
ChangeSiteViewerRoleResponse
emailThe address, as it is stored.
roleThe role it now has.
CheckoutRequestBody
intervalBilling interval, month or year.
planIdId of the plan to buy.
CheckoutResponse
checkoutUrlThe provider-hosted page to send the buyer to.
ClaimSitesRequest
Every site the caller holds a token for.
ClaimSitesResponse
Sites now owned by the caller.
Sites that were not claimed, each with a reason. A batch can be partly successful, so this is not an error case — the caller shows what it got and drops the rest from local storage.
ClaimedSite
siteIdULID of the site.
subdomainIts subdomain.
urlIts public URL.
ClientAddressResponse
addressThe address the API will rate-limit this caller by.
clientIpHeaderHeader the address was taken from. X-Forwarded-For means the chain was walked and
TrustedHops is what decided the answer; any other name means that header was read
directly and the hop count did not apply.
trustedHops^-?(?:0|[1-9]\d*)$ · requiredConfigured number of proxies in front of the API.
CompleteDeployRequest
nameA display name for the site, read by the client from the <title> of the
index.html being published.
Applied only to a site that has no name yet, and only on the call that takes a deploy live — so a redeploy never renames a site, and a retried completion never renames one either.
Cleaned by SiteNames before it is stored, and dropped silently when nothing usable is left. It is not worth failing a deploy whose files have already been verified over the contents of a title tag, and the owner can type a name on the settings page regardless.
CompleteDeployResponse
deployIdULID of the deploy that is now live.
docsModeWhether the site is read through the documents viewer rather than served as files.
Reported for the same reason as Name: the server decides it, from the files this
deploy actually holds (SiteModeDetection), and a client that guessed from what it uploaded
would be wrong exactly when it matters — the web app that went live inside the reader because its
index.html sat one folder too deep, with nothing on the finished card saying so.
edgelive when the edge has the deploy, pending when the deploy is live but the edge write did
not land yet — Cloudflare refused it or its API budget is spent. A pending deploy is not a failure: it
reaches the edge on its own, usually within the Retry-After the response carries, and calling
complete again is safe but not needed.
fileCount^-?(?:0|[1-9]\d*)$ · requiredNumber of verified files.
modeIsManualWhether the owner chose the mode by hand, in which case no deploy changes it.
nameWhat the site is called now, or null when it has none and its subdomain should be shown instead.
Reported rather than left for the client to infer, because only the server knows the answer: it cleans the name it is sent, and it refuses to overwrite a name the site already had. A client that assumed the title it sent is the name now stored would be wrong on every redeploy.
What the anonymous flow needs. A site is remembered in the browser before its first deploy starts — the claim token is returned once and storing it cannot wait — so the name is not known at that point and arrives here instead.
spaModeWhether unmatched paths are answered with the site's index.html.
statusAlways live on success.
totalBytes^-?(?:0|[1-9]\d*)$ · requiredTotal verified size in bytes.
urlPublic URL the site answers on. Content may take up to a minute to reach every edge.
CreateSiteFolderRequest
nameWhat to call the folder. Cleaned the way a site's name is.
parentIdFolder to create it inside. Omit it, or send "root", to create it at the top level — see
string SiteFolderAccess.RootToken for why a literal token rather than null.
CreateSiteRequest
subdomainThe caller's own choice of subdomain, checked by SubdomainFormat and ReservedNames and counted against int? Plan.MaxCustomSubdomains. Null or empty falls back to a generated one.
folderIdThe folder to file the new site in: a folder id of the caller's account, or root. Null or
empty means the top level, which is where every site started before this field existed. Naming a
folder the account does not hold is site_folder_not_found, and so is naming one at all
without an account.
CreateSiteResponse
claimTokenPlaintext claim token, present only for an anonymous site and returned only here. The server keeps nothing but its hash, so a client that loses it cannot recover ownership.
expiresAtWhen an unclaimed anonymous site is removed. Null once the site has an owner.
siteIdULID of the new site.
subdomainAllocated subdomain, without the parent domain.
urlPublic HTTPS URL the site will answer on once a deploy goes live.
CreateTokenRequest
expiresInDays^-?(?:0|[1-9]\d*)$ · requiredHow long it should last, or null for a token that never expires on its own.
nameWhat to call the token, so its owner can tell it from their others.
CreateTokenResponse
createdAtWhen it was issued.
expiresAtWhen it stops working on its own, or null.
idULID of the new token.
nameThe name it was given.
prefixIts first characters, which is what every later listing shows.
tokenThe plaintext. Returned exactly once and recoverable nowhere.
CurrentAnnouncement
iconThe mark drawn before it — ProductHunt, Gift, Sparkles or Megaphone — or
null for none. A page that does not know a value draws no mark.
idWhich bar this is.
linkLabelThe link's words, or null for no link.
linkUrlWhere the link goes — an https URL or a path on this site — or null.
messageThe sentence, plain text.
DeleteMeRequest
confirmEmailThe address the person signs in with, typed again as confirmation.
codeAn authenticator code, the other proof an immediate deletion accepts.
currentPasswordThe password, asked for only when Immediately is true.
immediatelyTrue to skip the grace period: erased within minutes, with no way back.
DeleteMeResponse
deletionDueAtWhen the deletion takes effect. Until then it can be called off.
DeleteSiteFolderResponse
folderIdThe folder that was removed.
foldersMoved^-?(?:0|[1-9]\d*)$ · requiredHow many folders were lifted one level.
movedToWhere its contents went: the deleted folder's own parent, or null when they are now at the root.
sitesMoved^-?(?:0|[1-9]\d*)$ · requiredHow many sites were lifted one level. Reported so the dashboard can say what happened rather than leaving somebody to find their sites somewhere they did not put them.
DeleteSiteResponse
siteIdULID of the deleted site.
subdomainIts subdomain, which stays reserved.
DeployDetail
completedAtWhen it reached a terminal state, or null while in flight.
createdAtWhen it was prepared.
deployIdULID of the deploy.
errorWhy it failed, when it did.
fileCount^-?(?:0|[1-9]\d*)$ · requiredFiles it holds.
isLiveWhether this is the deploy currently being served.
siteIdULID of its site.
statusLowercase status name.
totalBytes^-?(?:0|[1-9]\d*)$ · requiredIts size.
urlThe site's URL, present only when this deploy is live.
DeployFileContent
pathThe path, normalized — which is the spelling the manifest holds.
sha256Digest of the content as stored.
Sent so the editor can publish a change without re-reading anything: the new manifest is the old one
with this entry's digest replaced, and every other file is reused by prepare.
size^-?(?:0|[1-9]\d*)$ · requiredSize in bytes, as the manifest records it.
textThe file's text, or null when the bytes are not valid UTF-8.
Null rather than a lossy decode, so the dashboard can say the file cannot be edited here instead of offering an editor whose contents would overwrite the original with replacement characters.
DeployManifestPage
deployIdULID of the deploy the files belong to.
fileCount^-?(?:0|[1-9]\d*)$ · requiredFiles in the whole deploy, whatever the filter matched.
This page of matches, ordered by path.
filesKeptWhether the deploy is inside the retention window with its objects still on storage, the same answer
as filesKept on the site's version list. The list is answerable either way — it is read from
the row — so this is what separates "these files are here" from "these files were here".
matchingBytes^-?(?:0|[1-9]\d*)$ · requiredTheir total size, on the same terms.
matchingFiles^-?(?:0|[1-9]\d*)$ · requiredFiles the filter matched, equal to FileCount without one.
nextCursorPath to pass back as cursor for the following page, or null when this page was the last.
statusLowercase status name of that deploy.
totalBytes^-?(?:0|[1-9]\d*)$ · requiredSize of the whole deploy, whatever the filter matched.
DeploySummary
completedAtWhen it reached a terminal state, or null while in flight.
createdAtWhen it was prepared.
deployIdULID of the deploy.
errorWhy it failed, when it did.
fileCount^-?(?:0|[1-9]\d*)$ · requiredFiles it holds.
filesKeptWhether this version is inside the retention window with its files still on storage, and therefore whether it can be previewed or rolled back to.
It is a field rather than something a client works out because it cannot be worked out from the rest
of the response. site.trim_deploys keeps the plan's retainedDeploys most recently live
deploys, a rollback counting as going live, and deletes the objects of the rest, leaving the rows. A
version outside that window reads false at once, before the trim has run, because promote
refuses it by the same rule. The dashboard used to redraw that rule from a deploy's position in this
list, and disagreed with the server in both directions — and a plan whose retention was lowered then
raised has versions inside the window whose files went weeks ago.
string DeploySummary.Status does not answer it either: a superseded deploy may be fully stored or
entirely gone. Nothing about the row changes when its objects are deleted except this.
previewUrlURL serving this deploy on its own hostname, or null when there is no reachable preview of it.
Two reasons for null, and they are unrelated. The site's subdomain may be too long to leave room for a preview hostname (see int PreviewHostFormat.MaxSubdomainLength). Or the site's hostnames may not be answering at all — see bool SiteLifecycle.HostnamesServe(Site site): a preview resolves through the site's own hostname, so a tombstoned site has no reachable preview of any version, however sound the deploy behind it is. A site an administrator restores is exactly that, and reporting a URL for it was how the dashboard came to offer a history of versions none of which opened.
It works for any deploy whose files are still on storage, including one that was never published, and
stops working once retention removes them — the same condition promote reports as a 410. Nobody
is asked to log in: the URL is unlisted rather than access-controlled, and what protects it is the 80
bits of randomness in a ULID. A password-protected site's previews are behind that password like the
rest of it.
statusLowercase status name.
totalBytes^-?(?:0|[1-9]\d*)$ · requiredIts size.
DisableTwoFactorRequest
codeSix digits from the app.
passwordThe account's password.
EnableTwoFactorRequest
codeSix digits from the app; spaces are ignored.
EnforcingAccount
accountIdIts ULID.
accountNameWhat it is called.
EnvVarView
createdAtWhen it was first set.
last4The value's last four characters, or empty for a short value.
nameThe name.
updatedAtWhen its value last changed.
ExchangeCliCodeRequest
codeThe one-time code the browser handed to the loopback listener.
verifierThe verifier the command line generated and never sent through the browser.
ExchangeCliCodeResponse
createdAtWhen it was issued.
emailThat account's address, so the command line can say who it signed in as.
nameThe name it was given, which is what the command line called itself.
prefixIts first characters, which is what every later listing shows.
tokenThe plaintext access token. Returned exactly once and recoverable nowhere.
tokenIdULID of the token, so it can be matched to a row on the tokens page.
userIdThe account it speaks for.
ExportAccount
idThe account's id.
Its invoices, when they own it.
joinedAtWhen they joined it.
kindPersonal or team.
nameThe team's name.
planIdThe plan the account is on.
roleTheir role there.
Its subscriptions, when they own it.
ExportDeploy
completedAtWhen it finished.
createdAtWhen publishing started.
fileCount^-?(?:0|[1-9]\d*)$ · requiredHow many files.
idThe version's id.
statusWhere it stands.
totalBytes^-?(?:0|[1-9]\d*)$ · requiredHow many bytes.
ExportDomain
createdAtWhen it was added.
hostnameThe hostname.
statusWhere it stands.
ExportFormSubmission
fieldsWhat the visitor typed, as sent.
formNameThe form's name.
receivedAtWhen it arrived.
siteIdThe site it was sent to.
ExportInvoice
amountCents^-?(?:0|[1-9]\d*)$ · requiredWhat was charged, in cents.
amountRefundedCents^-?(?:0|[1-9]\d*)$ · requiredWhat was refunded, in cents.
currencyThe currency.
issuedAtWhen it was issued.
providerInvoiceIdThe payment provider's reference.
statusWhere it stands.
ExportOnboarding
completedAtWhen they answered.
marketingOptInAtWhen they agreed to product mail, if they did.
marketingOptOutAtWhen they last unsubscribed from it, if they did.
roleWhat they said they do.
sourceWhere they said they heard of it.
sourceDetailWhat they typed about that.
useCaseWhat they said they would use it for.
ExportPerson
createdAtWhen they signed up.
emailThe address they sign in with.
emailVerifiedAtWhen the address was confirmed.
googleLinkedWhether Google is a way in.
hasPasswordWhether a password is a way in.
idTheir id.
lastSeenAtWhen they last used the dashboard.
nameTheir name, if they gave one.
ExportSite
accountIdThe account it belongs to.
createdAtWhen it was made.
Its versions, without their files.
Its custom domains.
idThe site's id.
nameThe name its owner gave it.
statusWhere it stands.
subdomainIts address under the content domain.
ExportSubscription
canceledAtWhen it was cancelled, if it was.
createdAtWhen it started.
currentPeriodEndWhen the paid period ends.
planIdWhat it pays for.
seats^-?(?:0|[1-9]\d*)$ · requiredHow many seats.
statusWhere it stands.
FindCliDeviceRequest
userCodeThe short code as typed, in any case and with or without the dash.
FindCliDeviceResponse
clientNameWhat the waiting command line calls itself.
expiresAtWhen the request stops being approvable.
fromThisAddressWhether it asked from the same address as the browser now looking.
requestedAtWhen the command line asked.
requestedFromCountryThe two-letter country of that address, or null when not known.
requestedFromIpThe address it asked from, or null when that is not known.
ForgotPasswordRequest
emailThe address the account signs in with.
FormSubmissionPage
page^-?(?:0|[1-9]\d*)$ · requiredZero-based index of the page returned.
pageSize^-?(?:0|[1-9]\d*)$ · requiredHow many rows a page holds, after the cap was applied.
The page, newest first.
total^-?(?:0|[1-9]\d*)$ · requiredHow many this form has in total, so the reader knows there is more.
FormSubmissionRow
deployIdWhich deploy was live at the time, which is what explains a column being empty: the field did not exist in the HTML that was serving then.
fieldsWhat the visitor typed, as the JSON object it was stored as.
idULID minted at the edge when the submission arrived.
metaPage, host, country, truncation and the Turnstile verdict, as stored.
receivedAtWhen the edge accepted it, not when the row was written.
spamSourceWho called it spam — system, user, or nobody.
FormerSubdomain
retiredAtWhen the site stopped answering on it.
subdomainThe former subdomain, which redirects to the current one.
FunctionsUsageResponse
callsThisMonth^-?(?:0|[1-9]\d*)$ · requiredFunction calls this calendar month across every site, up to about an hour and a half behind. Resets with filesResetAt.
maxCallsPerMonth^-?(?:0|[1-9]\d*)$ · requiredCalls the account's sites may make together each calendar month, seats included.
maxSites^-?(?:0|[1-9]\d*)$ · requiredSites that may run functions at once. A deploy that would add one past it is refused.
sites^-?(?:0|[1-9]\d*)$ · requiredSites whose live version has functions, which is what maxSites bounds.
suspendedWhether this month's calls are spent and every function of the account answers 429.
GoogleOneTapRequest
credentialThe ID token (JWT) Google's Identity Services callback handed the browser.
GrantResponse
accountBytes^-?(?:0|[1-9]\d*)$ · requiredExtra storage it adds, in bytes, or null when it adds none.
allowsFeedbackWhether it switches on comments, for the same reason.
allowsInvitedViewersWhether it switches on private sharing by email, so the page can say where that came from on a tier that does not include it.
allowsPasswordProtectionWhether it switches on password protection, for the same reason.
expiresAtWhen it runs out, or null when it does not.
maxCustomDomains^-?(?:0|[1-9]\d*)$ · requiredExtra custom domains it adds.
maxSites^-?(?:0|[1-9]\d*)$ · requiredExtra sites it adds, or null when it adds none.
nameWhat to call it. The campaign's name where it came from one, and a generic label otherwise — never the administrator's own note, which is written for the console.
suppressesBadgeWhether it takes the Drop2Run badge off this account's sites.
writeOpsPerMonth^-?(?:0|[1-9]\d*)$ · requiredExtra publishing operations a month, or null.
HealthResponse
databasePostgres connectivity: up or down.
statusOverall status: ok or degraded.
InspectAccountLinkRequest
purposeverify for a confirmation link, reset for a password reset link, change for a
change-of-address link.
tokenThe token the mailed link carried.
InviteMemberRequest
emailAddress to invite. Compared against the accepter's own before they are let in.
roleWhat accepting grants: Owner or Member. Absent means member.
Absent rather than required, and defaulting to the lesser of the two, because an omitted field must not hand out authority nobody asked for — the same rule every capability column on a plan follows.
InviteResponse
acceptUrlThe link. Returned here and nowhere else — only its hash is stored, so this response is the one chance to copy it, which is what lets an owner pass it on when mail does not arrive.
emailThe address it was sent to.
expiresAtWhen it stops working.
idIts id, for revoking.
InviteRow
emailThe address it was sent to. The link only works for this one.
expiresAtWhen it stops working on its own.
idIts id, which is what withdrawing it names.
roleWhat accepting it would grant.
InvoiceRow
amountCents^-?(?:0|[1-9]\d*)$ · requiredAmount in the smallest unit of Currency.
amountRefundedCents^-?(?:0|[1-9]\d*)$ · requiredHow much of it has been given back. Shown beside the charge rather than instead of it, so a partial reversal reads as what it is — a status alone cannot say how much of the money came back.
currencyISO 4217 code.
hostedUrlLink to the provider's own copy, or null.
idOur own id for the invoice.
issuedAtWhen the provider issued it.
periodEndEnd of the period covered, or null.
periodStartStart of the period covered, or null.
statusOne of the InvoiceStatus names.
InvoicesResponse
The account's invoices, newest first.
ListSitesResponse
page^-?(?:0|[1-9]\d*)$ · requiredZero-based index of this page.
pageSize^-?(?:0|[1-9]\d*)$ · requiredHow many rows a full page holds.
The rows on this page, in the order that was asked for.
total^-?(?:0|[1-9]\d*)$ · requiredHow many sites match, across every page — which is what the pager is against. Equal to TotalOwned when no search was asked for.
totalOwned^-?(?:0|[1-9]\d*)$ · requiredHow many sites the caller owns, ignoring any search.
Both numbers, because the listing says both: the page header counts what the account holds and the line above a searched list counts what matched. One number cannot carry that sentence, and a client holding the other from an earlier response has a number that a deletion can make wrong.
ListTokensResponse
What colleagues hold on the same account, and only what an owner is entitled to know about them. Empty for a member, and empty for an owner whose colleagues have none.
A separate list rather than the same rows with fields blanked out, because a row that is sometimes missing its prefix is a row whose type is a lie — and the screen showing it has to branch on something either way.
The caller's own tokens on this account, newest first, including revoked ones.
ManifestEntry
pathPath relative to the deploy root, as the client sees it.
sha256SHA-256 of the content, lowercase hex.
size^-?(?:0|[1-9]\d*)$ · requiredExact length of the content in bytes — the length that will be uploaded. 0 only for an empty file, whose checksum is the SHA-256 of zero bytes.
ManifestFile
pathIts path within the site, already normalized and always /-separated.
sha256SHA-256 of the content, lowercase hex — what the upload was verified against.
size^-?(?:0|[1-9]\d*)$ · requiredIts size in bytes.
MeExport
Every account they are in, with billing for the ones they own.
exportedAtWhen the file was made.
What visitors sent through those sites' forms, as kept (ninety days).
The person.
The sites of the accounts they own.
MeResponse
accountIdThe account this session is acting on.
accountNameWhat the account is called, or null for a personal one nobody has named.
Sent because every screen under /account is now about an account rather than about the person
reading it, and a page headed with somebody's own name while describing a shared tier is the exact
confusion the team screens were redesigned to remove.
emailEmail from Google.
Extra quota this account holds outside its tier, one entry each, oldest first.
The figures in Plan already include these — every one of them is the effective number the server enforces — so this is not a second set of limits to add up. It is what lets a page say why a figure is larger than the tier it names, which is the difference between a benefit and an apparent bug in the dashboard. Empty for almost every account.
nameDisplay name from Google, if any.
onboardingpending while this person has neither answered nor skipped the first-visit questions, and
done once they have.
On the person rather than the account, like the name and the address beside it: somebody in two
accounts is asked once. Everybody who had an account before the questions existed reads as
done, because the migration that added the table gave them a skipped row (A14).
overLimitUntilWhen the account's grace for being over its plan runs out, or null while it fits.
Non-null means something will be cut on that date — the oldest sites are put to sleep and the oldest custom domains are removed, only as far as it takes to fit. It is served so the dashboard can say so beforehand: nobody should learn about this from a site going quiet.
The quota tier currently applied to this user.
recoveryCodesLeft^-?(?:0|[1-9]\d*)$ · requiredHow many unused two-factor recovery codes this person has, or null while two-factor is off. On the session rather than only on the profile because the reminder it drives — three or fewer — is shown on the site list, which does not read the profile.
roleWhat the signed-in person may do on that account: Owner or Member.
Served so the dashboard can leave out controls the caller cannot use — a delete button, the billing pages — rather than showing them and reporting a refusal afterwards. It is not the permission: every one of those actions is refused at the handler regardless of what the page drew, and a client that ignored this field would gain nothing but a worse error message.
seats^-?(?:0|[1-9]\d*)$ · requiredHow many seats the account is paying for, which is what its raised ceilings were computed from.
One on every tier not sold by the seat, where it is a constant rather than a measurement. It is not the number of members: seats are bought and members are people, and the two moving independently is the whole reason inviting somebody does not silently change an invoice.
How much of the plan is currently used.
userIdULID of the signed-in user.
MemberRow
emailTheir address, which is how a colleague recognises them.
founderWhether they created the account. A founder cannot be removed or demoted while the plan is held in their name, so the members screen offers neither for this row.
joinedAtWhen they were added.
nameTheir display name, or null when Google gave none.
roleWhat they may do here.
twoFactorWhether they have two-factor on — the column an owner reads before requiring it, and a member reads to see whether the rule would block them.
userIdTheir ULID, which is what removing them names.
MembersResponse
Invitations still standing. Spent and withdrawn ones are history, not a list.
People who may act on it, oldest first.
requireTwoFactorAtSince when the owner has required two-factor of every member, or null while they have not.
tokensOfUnprotectedMembers^-?(?:0|[1-9]\d*)$ · requiredAccess tokens on this account held by members without two-factor. Requiring two-factor does not stop them, so the owner is told before turning it on.
MoveSiteFolderItemsRequest
folderIdsFolders to move under it. May be empty when only sites move.
siteIdsSites to file there. May be empty when only folders move.
targetIdWhere everything goes: a folder id, or "root" for the top level. Required — see
string SiteFolderAccess.RootToken for why the root is a token rather than an absent value.
MoveSiteFolderItemsResponse
foldersMoved^-?(?:0|[1-9]\d*)$ · requiredFolders that changed parent, counted the same way.
sitesMoved^-?(?:0|[1-9]\d*)$ · requiredSites that changed folder. Fewer than were sent when some were already there, which is not an error.
targetIdThe folder everything is now in, or null for the top level.
OfferedPromotion
allowsFeedbackWhether claiming it switches on comments.
allowsInvitedViewersWhether claiming it switches on private sharing by email.
allowsPasswordProtectionWhether claiming it switches on password protection.
codeIts code, or null when there is none to type.
deltaAccountBytes^-?(?:0|[1-9]\d*)$ · requiredExtra storage it gives, or null when it gives none.
deltaMaxCustomDomains^-?(?:0|[1-9]\d*)$ · requiredExtra custom domains it gives.
deltaMaxSites^-?(?:0|[1-9]\d*)$ · requiredExtra sites it gives, or null when it gives none.
deltaSitesPerDay^-?(?:0|[1-9]\d*)$ · requiredExtra sites a day the account may create, or null. Only ever set on a campaign aimed at named accounts, so only an account the operator chose ever reads a figure here.
deltaWriteOpsPerDay^-?(?:0|[1-9]\d*)$ · requiredExtra publishing operations a day, or null.
deltaWriteOpsPerMonth^-?(?:0|[1-9]\d*)$ · requiredExtra publishing operations a month, or null.
endsAtWhen claiming closes, or null when it does not.
grantExpiresAfterDays^-?(?:0|[1-9]\d*)$ · requiredHow long what it gives lasts, or null for good.
idThe campaign, which is what a button with no code to type sends back.
nameWhat to call it on the banner.
placesLeft^-?(?:0|[1-9]\d*)$ · requiredHow many accounts may still claim it, or null when any number may. Read a moment ago and acted on a moment later, so it is a number to show rather than a number to trust — the redeem endpoint is what decides, and it decides in one statement.
suppressesBadgeWhether claiming it takes the Drop2Run badge off.
OfferedPromotionsResponse
What this account can claim, the ones closing soonest first and the open-ended ones last.
PasswordSignInRequest
emailThe address the account was created with.
passwordThe password.
turnstileTokenA bot check token, needed only after turnstile_required.
PendingCheckoutRow
createdAtWhen the checkout began.
intervalThe billing interval chosen.
planIdThe plan the checkout is for.
statusopen or completed.
PendingEmailResponse
emailThe address being moved to.
expiresAtWhen the link stops working.
requestedAtWhen it was asked for, so the page can say how long ago the link went out.
PlanChangeRow
fromIntervalThe billing term before, or null when there was none.
fromPlanIdThe tier before.
fromSeats^-?(?:0|[1-9]\d*)$ · requiredSeats paid for before; one on every tier not sold by the seat.
occurredAtWhen it happened.
reasonWhy it moved: one of PlanChangeReason.
toIntervalThe billing term after, or null when there is none.
toPlanIdThe tier after.
toSeats^-?(?:0|[1-9]\d*)$ · requiredSeats paid for afterwards.
PlanHistoryResponse
The account's tier changes, newest first.
PlanResponse
allowAnalyticsExportWhether the dashboard offers to save this tier's traffic figures as files.
Another statement about what the tier is sold with rather than a lock: the files are assembled in the browser from the traffic response the page already holds, so a reader who can see the page can read the same numbers off it — see bool Plan.AllowAnalyticsExport.
allowBrowserEditWhether the dashboard lets an owner edit a file of their site in the browser.
A gate rather than packaging, like the flag above: the endpoint the editor reads a file through is refused outright for a tier without it.
allowFeedbackWhether a site on this tier can take comments on its pages (docs/IMPLEMENTATION-PLAN.md §16.7).
Served so the pricing page and the marketing pages say which tiers include comments from the table, never from a sentence: the tiers that carry it are set in the admin console and change without a release.
allowInvitedViewersWhether a site on this tier may be shared with named people, each signing in with their own account. A capability beside AllowPasswordProtection — the two are the paid answers to "who can see this site" — and served for the same reason: the pricing page lists it beside the password.
allowPasswordProtectionWhether a site on this tier may be put behind a password. The first capability on this record rather than a quantity, so it reads as a boolean instead of a limit of zero: the tier either offers the feature or does not, and "0 passwords" would describe a countable resource nobody has any of.
Served here for the same reason every number above is — the pricing page and the site settings form both have to know, and a client that hardcoded which tiers had it would be wrong the first time an operator flipped the column.
allowQrCodeWhether the dashboard offers a QR code for the addresses of sites on this tier.
Served rather than decided in the browser for the same reason the flag above is, and for one more: this is the only thing that decides the feature at all. The code is drawn from an address that is already public, so the tier's answer is a statement about what the tier is sold with, not a lock — see bool Plan.AllowQrCode.
allowScheduledExpiryWhether an owner on this tier may schedule when one of their sites comes down.
Unlike the two flags above, this one is a real gate rather than a statement about packaging: the server refuses to set a date for a tier without it. Served all the same, so the pricing page can list it and the dashboard can explain the absence rather than failing on submit.
allowTrafficBreakdownWhether this tier's traffic page lists top pages, referrers, countries and broken links, and filters by them. Served so the pricing page and the locked panels can name the tier that includes them.
allowTrafficDetailWhether this tier's traffic page splits people from bots and AI, and shows devices, browsers, campaigns and edge speed.
analyticsDays^-?(?:0|[1-9]\d*)$ · requiredHow many days of a site's own traffic this tier lets its owner see, or zero when it includes none.
A count where bool PlanResponse.AllowPasswordProtection is a flag, because there is something to meter here: the difference between tiers is how far back the history reaches, and a boolean would need a second field to say that. Zero reads as "not on this tier" rather than as a quantity nobody has, which is why the pricing page renders it as words rather than as the number.
badgeTextShort label shown against the tier, or null for none. See string? Plan.BadgeText.
currencyISO 4217 code the two price fields are counted in.
displayOrder^-?(?:0|[1-9]\d*)$ · requiredWhere the tier sits on the pricing page, lowest first.
idPlan id, as stored.
isExclusiveWhether this tier is not on the pricing page, and reaches the caller only because it was agreed with them.
Always false on the anonymous route, which returns the listed tiers and therefore has nothing to say here. It exists so the dashboard can label the card: a reader meeting a price nobody else is offered, beside prices everybody is, would otherwise have no way to tell which is which — and would reasonably wonder why they cannot find it on the pricing page.
Not the same question as bool PlanResponse.IsPurchasable. A tier can be agreed before its prices are set, which is exclusive and not yet buyable, and the card has to say both.
isPurchasableWhether the tier can be bought right now. Separate from being listed: a tier that is listed and not purchasable shows its price and its limits with no button, which is how a tier is announced before there is a checkout behind it. See bool Plan.IsPurchasable.
isTeamWhether the two prices are the cost of one seat rather than of one period.
Served publicly because the pricing page cannot render the tier without it: fifteen dollars a seat and fifteen dollars a period are the same number in the same field and three times apart in what a customer pays. A page that showed the column would put this tier beside the one above it at an identical price.
lifetimeDays^-?(?:0|[1-9]\d*)$ · requiredDays before the site is deleted, or null when it is kept for good.
maxAccountBytes^-?(?:0|[1-9]\d*)$ · requiredMaximum bytes the account may hold across every site and every kept version, or null when the tier has no total. Null on the anonymous tier, which has no owner to total by. See long? Plan.MaxAccountBytes.
maxAccountWriteOpsPerMonth^-?(?:0|[1-9]\d*)$ · requiredNew or changed files the account may publish in a calendar month, or null when the tier is not bounded by month. The one limit on this page that is a cost rather than a capacity: republishing a file that has not changed spends nothing against it.
maxCustomDomains^-?(?:0|[1-9]\d*)$ · requiredMaximum hostnames of the customer's own that one account may be served on, counted across every site it owns. Zero means the tier does not include the feature, which is what both free tiers are seeded with — so the pricing page reads this as a capability rather than as a quantity. Never null, unlike the quotas above it: there is no unlimited version of a resource billed monthly per unit. Distinct from int? PlanResponse.MaxCustomSubdomains, which counts names on our own content domain. See int Plan.MaxCustomDomains.
maxCustomSubdomains^-?(?:0|[1-9]\d*)$ · requiredMaximum sites one owner may have picked their own subdomain for, or null when the tier does not limit that at all. See int? Plan.MaxCustomSubdomains.
maxFileBytes^-?(?:0|[1-9]\d*)$ · requiredMaximum size of a single file, in bytes.
maxFiles^-?(?:0|[1-9]\d*)$ · requiredMaximum files in one deploy.
maxFormSubmissionsPerMonth^-?(?:0|[1-9]\d*)$ · requiredMaximum form submissions one account may take in a calendar month, across every site it owns. Zero means the tier does not include the feature, and every tier is seeded zero — the figure worth selling is not known yet, so it ships off and an operator raises it per row once the counter has something to read. The pricing page therefore renders this as a capability until somebody sets a number. See int Plan.MaxFormSubmissionsPerMonth.
maxProxyRequestsPerMonth^-?(?:0|[1-9]\d*)$ · requiredRequests one account's sites may proxy to their owners' upstreams in a calendar month. Zero means the tier does not include the proxy. See int Plan.MaxProxyRequestsPerMonth.
maxSeats^-?(?:0|[1-9]\d*)$ · requiredMost seats it can be held with, or null for no ceiling.
maxSiteBytes^-?(?:0|[1-9]\d*)$ · requiredMaximum total size of one deploy of one site, in bytes, or null when the tier does not bound a single publish and lets the account total do it instead. Not a storage limit either way: it is weighed against a single publish, and every kept version is stored whole. MaxAccountBytes is the storage one.
maxSiteComments^-?(?:0|[1-9]\d*)$ · requiredThe most comments one site on this tier may hold, deleted ones not counted. Only meaningful where AllowFeedback is on; served on every tier like the other ceilings.
maxSiteViewers^-?(?:0|[1-9]\d*)$ · requiredHow many people one invite-only site may list, its owner included. Read only where AllowInvitedViewers is on; a figure on a tier without the feature describes nothing.
maxSites^-?(?:0|[1-9]\d*)$ · requiredMaximum sites one owner may have, or null when the tier has no owner to count by — the anonymous tier, whose sites belong to nobody.
minSeats^-?(?:0|[1-9]\d*)$ · requiredFewest seats the tier is sold with, which is what turns a seat price into an entry price.
nameWhat the tier is called on screen, falling back to the id when a row has never been named. Served rather than written into the pricing page so that a tier added to the table appears with its own name instead of an id, which is what makes a new tier a database insert rather than a release.
parentPlanIdThe tier this one is built on, or null when it stands alone.
Every quota above is already the effective one — inheritance is materialised on the row, so nothing reading this response has to resolve anything. This field is here for what the pricing page says rather than for what it computes: a tier built on another is listed as everything that one includes plus what it adds, and the rows that repeat the parent's figures are left off the card. Without the link the page would have to guess that relationship from the numbers, and two tiers that happen to share a figure are not the same claim as one built on the other.
Null on the card when the parent is not itself public: there is no listed tier to name, so the card falls back to listing every row.
perSeatAccountBytes^-?(?:0|[1-9]\d*)$ · requiredStorage each seat past the minimum adds, or null when storage does not scale with seats.
The per-seat figures are served for one reason, and it is not decoration. This endpoint is public, so it has no account and therefore no seat count — it can only state the tier's base. The dashboard states the effective figure for the account reading it. Without the delta beside the base, the two pages say different numbers for the same plan and the promise that the pricing page shows what the service enforces stops being true.
perSeatMaxCustomDomains^-?(?:0|[1-9]\d*)$ · requiredHostnames of the customer's own each seat past the minimum adds. Zero says a seat buys none, which is where every tier starts and what the free tiers stay at.
perSeatMaxFormSubmissionsPerMonth^-?(?:0|[1-9]\d*)$ · requiredForm submissions a month each seat past the minimum adds to the account's allowance. Zero says a seat buys none, which is every tier but Team.
perSeatMaxProxyRequestsPerMonth^-?(?:0|[1-9]\d*)$ · requiredProxied requests a month each seat past the minimum adds. Zero says a seat buys none.
perSeatMaxSites^-?(?:0|[1-9]\d*)$ · requiredSites each seat past the minimum adds, or null when they do not scale.
perSeatWriteOpsPerDay^-?(?:0|[1-9]\d*)$ · requiredDaily budget each seat adds, or null when it does not scale.
perSeatWriteOpsPerMonth^-?(?:0|[1-9]\d*)$ · requiredMonthly budget each seat adds, or null when it does not scale.
priceCentsMonth^-?(?:0|[1-9]\d*)$ · requiredPrice of one month in the smallest unit of Currency, or null when the tier is not sold by the month. Null rather than zero on the free tiers: they are not priced at zero, they are not on sale.
priceCentsYear^-?(?:0|[1-9]\d*)$ · requiredPrice of one year, or null when the tier is not sold by the year.
prioritySupportWhether support requests from accounts on this tier are answered ahead of the queue.
Served because the pricing page lists it, and for no other reason: nothing in the API branches on it. It is the one field here that no endpoint enforces, because what it describes is a promise kept by whoever answers the mail — see bool Plan.PrioritySupport.
retainedDeploys^-?(?:0|[1-9]\d*)$ · requiredHow many recent deploys stay available.
showsBadgeWhether sites on this tier carry the Drop2Run badge in their served HTML.
The one field on this record that describes something the platform does to a site rather than something the site is allowed to do, which is why it reads as "shows" rather than "allows". The pricing page states it as a row like any other limit, because it is a difference between the tiers a reader has to know before they upload rather than after.
sitesPerIpPerDay^-?(?:0|[1-9]\d*)$ · requiredMaximum new sites one network may create per day, or null when the tier is not counted by address. Abuse protection rather than a product limit, so nothing is expected to display it.
taglineOne line under the name, or null to show none. See string? Plan.Tagline.
PlansResponse
anonymousPlanIdTier applied to a site created without signing in.
contentDomainApex domain a site's subdomain sits under, for example dropto.live. Served here rather than
hardcoded in the frontend for the same reason every number above is: it is server configuration, and a
client that guessed it would show the wrong suffix the moment the domain changed.
Every tier, smallest first.
signedInPlanIdTier applied once the visitor has an account.
PollCliDeviceRequest
deviceCodeThe long code the command line was given when it opened the request.
PollCliDeviceResponse
createdAtWhen it was issued.
emailThat account's address, so the command line can say who it signed in as.
nameThe name it was given, which is what the command line called itself.
prefixIts first characters, which is what every later listing shows.
tokenThe plaintext access token. Returned exactly once and recoverable nowhere.
tokenIdULID of the token, so it can be matched to a row on the tokens page.
userIdThe account it speaks for — whoever approved the request.
PortalResponse
portalUrlWhere to send the customer to manage their card and receipts.
PrepareDeployRequest
Every file the client intends to upload.
batchesWhether the client can send batch permits — several small files in one request. A client that does not set it receives one permit per file. Setting it is a request, not a guarantee: the server may still answer with single permits only.
PrepareDeployResponse
Batch permits, each covering several small files sent as one body. Empty unless the request asked for batches and they are enabled; a file is in exactly one of Upload and this.
deployIdULID of the new deploy; part of every R2 key it writes.
reused^-?(?:0|[1-9]\d*)$ · requiredHow many files the live deploy already holds byte-identical. These are absent from Upload and are copied server-side when the deploy completes.
total^-?(?:0|[1-9]\d*)$ · requiredFiles in the whole deploy: Reused plus what must be uploaded.
One upload permit per file sent on its own.
uploadUrlThe single endpoint every permit is presented to. Sent with the response rather than compiled into the client, because it is a different host in development, in tests and in production — and because a client that knew the address without being told would still know it after we moved.
batchConcurrency^-?(?:0|[1-9]\d*)$How many of Batches to send at once; null when there are none. The upload Worker can hold only six R2 writes open per request, so this is what decides how fast many small files go, and it is set here so it can be tuned without a client release. Single permits are not affected.
unchangedTrue when the manifest describes exactly what is already live, so no deploy was created. The caller
has nothing to upload and must not call complete: DeployId is the deploy
already serving, and completing it again would only rewrite the mapping to where it already points.
urlPublic URL of the site, sent only when Unchanged is true. That answer is the end of the deploy, and without it the caller would have to ask a second endpoint just to show the link.
warningsThings about this deploy the caller should be told although it was accepted, or null when there are none —
today only that _functions/ will not run on this site (docs/briefs/FUNCTIONS-BRIEF.md D23).
PreviewPromotionRequest
codeThe code, as typed. Folded to upper case here, so the case somebody used does not matter. Bounded by the same length an operator may give one.
PreviewTicket
actionThe URL to post the ticket to, as the form field ticket, targeting the preview frame.
expiresAtWhen the frame's access runs out and a new ticket is needed.
ticketThe signed ticket. Accepted for one minute.
ProblemDetails
detailinstancestatus^-?(?:0|[1-9]\d*)$titletypeProfileResponse
accountCount^-?(?:0|[1-9]\d*)$ · requiredHow many accounts they are a member of. Sent because it is the sentence that tells a reader why this page is separate from the account pages, and one number is cheaper than a list nobody reads here.
createdAtWhen they first signed in here.
emailThe address they are written to and sign in with.
emailVerifiedWhether that address has been proven to reach them.
googleLinkedWhether Google is one of their ways in.
googleLinkedAtWhen Google became one, or null when it is not one — or when it became one before this was recorded.
hasPasswordWhether a password is one of their ways in. False for somebody who has only ever used Google, for whom the page offers to set one rather than to change one.
nameTheir display name, shown to people on their teams, or null when they have none.
passwordChangedAtWhen the password was last set, or null when there is none.
productEmailWhether they get product email now: consent given and not withdrawn since. Mail about their account and sites is not affected either way.
userIdThe person's ULID, which is the identifier worth quoting in a support mail.
PromoteDeployResponse
deployIdULID of the deploy that is now live.
edgelive when the edge has the deploy, pending when the rollback is committed but the edge
write did not land yet; it gets there on its own, as on complete.
fileCount^-?(?:0|[1-9]\d*)$ · requiredFiles in the promoted deploy.
statusAlways live on success.
totalBytes^-?(?:0|[1-9]\d*)$ · requiredIts total size in bytes.
urlPublic URL the site answers on. Content may take up to a minute to reach every edge.
ProxyAllowance
perMonth^-?(?:0|[1-9]\d*)$ · requiredRequests the plan allows a month; zero on a plan without the proxy.
resetsAtWhen the count starts again: the first instant of next month, UTC.
suspendedWhether the month is spent and every proxy route of the account answers 429.
used^-?(?:0|[1-9]\d*)$ · requiredRequests counted so far this month, every site of the account together. Runs up to about an hour and a half behind.
ProxyLogRow
abortedWhether the visitor left before the response ended.
atWhen it was answered.
bytes^-?(?:0|[1-9]\d*)$ · requiredResponse bytes passed on.
durationMs^-?(?:0|[1-9]\d*)$ · requiredMilliseconds from the proxy receiving it to the response ending.
errorThe proxy's own error code, or empty when the status came from the upstream.
methodRequest method.
pathSite path, without the query.
status^-?(?:0|[1-9]\d*)$ · requiredStatus returned to the visitor.
ProxyRouteView
fromThe site path, ending in /* or holding :name segments.
toThe target, https://host/path.
RecoverTwoFactorRequest
codeOne recovery code; case, spaces and dashes do not matter.
RecoveryCodesResponse
recoveryCodesTen codes, each XXXX-XXXXXX.
RedeemPromotionRequest
codeThe code, as typed. Folded to upper case here, so the case somebody used does not matter.
promotionIdThe campaign's id, for an offer that was listed — a button rather than something to type. Refused for a
campaign whose audience is Code: there the code is the only way in.
RedeemPromotionResponse
expiresAtWhen the grant runs out, or null when it does not.
nameIts name, so the page can say what was applied without a second call.
promotionIdThe campaign claimed.
RejectedClaim
reasonOne of the Errors codes: site_not_found or quota_exceeded.
siteIdULID that was attempted.
RemoveSiteDomainResponse
hostnameThe hostname that stopped serving.
idULID of the domain that was removed.
RemoveSiteViewerResponse
emailThe address removed, as it was stored.
total^-?(?:0|[1-9]\d*)$ · requiredHow many people the list still holds, the owner included.
RenameAccountRequest
nameWhat to call the account, or null to clear the name.
ReplyToSiteFeedbackRequest
bodyThe reply, plain text.
resolveWhether to resolve the thread with the reply; false by default.
ReportAbuseRequest
reasonWhat is wrong with it.
urlFull address of the offending page.
reporterEmailOptional contact address. Deliberately not required: insisting on one costs more reports than it gains in follow-up.
ReportAbuseResponse
reportIdReference for the report. Given back so a reporter following up has something to quote, and so a retried submission can be recognised as a duplicate by hand.
ReportProblemRequest
messageWhat happened, in the person's words.
emailWhere to answer. Read only without a session; a signed-in user's own address is used.
turnstileTokenThe bot check's token. Required without a session, ignored with one.
ReportProblemResponse
reportIdReference for the report, for the person to quote if they write again.
ResendDeletionLinkRequest
emailThe address the person signs in with.
ResendSiteViewerInvitationRequest
emailThe address on the list to mail again, in any case.
ResendSiteViewerInvitationResponse
emailThe address mailed, as stored.
emailedAtWhen the mail was queued; another may be sent a day after this.
ResetPasswordRequest
passwordThe new password.
tokenThe token the mailed link carried.
RevokeTokenResponse
idULID of the token that no longer works.
revokedAtWhen it stopped working, which is unchanged if it already had.
SaveOnboardingRequest
buildsWhat their sites are made with. One or several.
completedWhether this is the last step's send, so the questions are done.
roleWhat they do.
sourceWhere they heard about us.
sourceDetailWhat they typed beside a source that offers a box; required for other.
useCaseWhat they will publish first.
SetAccountSecurityRequest
requireTwoFactorWhether every member must sign in with two-factor.
SetProductEmailRequest
subscribedTrue to receive product email, false to stop it.
SetSiteEnvVarRequest
valueThe value, in plain text — sealed on arrival and never shown back.
SignUpRequest
emailThe address to create the account with.
passwordThe password, checked against the rules in PasswordPolicy.
turnstileTokenThe token the page's Turnstile widget produced.
returnToWhere to send the person once the address is confirmed: a path on the dashboard origin, checked by the same rule the sign-in pages apply. Anything that is not one is dropped, not refused.
SiteClaim
claimTokenThe plaintext token issued when the site was created.
siteIdULID of the site.
SiteCommentBlockRow
blockedAtWhen they were blocked.
commentsRemoved^-?(?:0|[1-9]\d*)$ · requiredHow many of their comments were deleted with the block.
emailTheir address, or null once the account is gone.
nameThe name their comments showed.
userIdWho, for unblocking.
SiteCommentBlocksResponse
page^-?(?:0|[1-9]\d*)$ · requiredThe page returned, from 0.
pageSize^-?(?:0|[1-9]\d*)$ · requiredRows per page.
Most recent first.
total^-?(?:0|[1-9]\d*)$ · requiredEverybody blocked on the site.
SiteDetail
analyticsDays^-?(?:0|[1-9]\d*)$ · requiredHow many days of traffic this site's plan allows seeing, or zero when it includes none. Sent for the same reason as the flag above: the page can state what the plan covers instead of requesting the figures and rendering a refusal.
analyticsExportAvailableWhether this site's plan is sold with the traffic export. Read from the site's own plan rather than from the signed-in account's, because the two differ — an anonymous site is on the anonymous tier whoever is looking at it.
anonymousWhether the site has no account behind it.
Stated rather than inferred, and it replaces an inference the dashboard was making from ExpiresAt being set. That proxy held only while an expiry meant one thing: now that an owner can schedule a takedown on a site of their own, a paid site with a date on it would have read as anonymous and been told it gets deleted after a few days.
browserEditAvailableWhether this site's plan lets its owner edit a file in the browser. Sent so the file list can leave the Edit action out rather than offering one the server refuses.
commentAudienceWho the owner chose may comment — Off, Invited or Anyone. The stored choice; it takes
effect only where FeedbackAvailable is true and, for Invited, while the site is
invite-only, which the Sharing tab says in words.
createdAtWhen the site was created.
customDomainAllowance^-?(?:0|[1-9]\d*)$ · requiredHow many hostnames of the customer's own this site's plan allows across the account, or zero when it includes none.
Sent here rather than looked up from the public plans list, which is where the dashboard read it and
where it is not always findable: GET /plans filters to public tiers, so a site on a plan cut
for one account matched nothing and the section rendered as a heading with nothing underneath —
exactly the account most likely to have been given an allowance. The same argument as
PasswordProtectionAvailable, which is why it sits beside it.
The most recent deploys, newest first.
docsModeWhether the site is served through the documents viewer.
expiresAtWhen an unclaimed anonymous site is removed, or null once claimed.
expiryActionWhat the expiry does when it falls due, Pause or Delete. Meaningless while
ExpiresAt is null, and sent anyway so the form has something to show when the
owner sets a date.
feedbackAvailableWhether this site's plan includes comments. Sent for PasswordProtectionAvailable's reason: the control shows disabled with a reason rather than failing on submit.
folderIdThe folder it is filed in, or null when it sits at the root of the listing.
The same field SiteSummary carries. Sent here as well so the site's own page can put that
folder in its trail and return to it — after a removal, too — instead of to the root of the listing,
which is where somebody who opened the site from inside a folder did not come from.
The names the site used to answer on, newest first, each redirecting to it.
formsAvailableWhether the account's tier includes forms at all.
Reported beside the switch for the reason PasswordProtectionAvailable is: the dashboard has to tell "off" apart from "not yours to turn on", and a control that looks available and then refuses is worse than one that says why.
formsEnabledWhether the owner has switched form submissions on for this site.
invitedOnlyWhether only the people on the site's list may see it. Never true together with PasswordProtected.
invitedViewersAvailableWhether this site's plan offers invite-only sites. Sent for PasswordProtectionAvailable's reason: the Sharing tab shows the third choice disabled with a reason rather than offering it and failing.
lastActiveAtWhen it last received a deploy.
liveDeployIdThe deploy being served, or null.
maxSiteViewers^-?(?:0|[1-9]\d*)$ · requiredHow many people this site's plan lets the list hold, the owner included — and, per site, how many invitations it may mail in a day.
modeIsManualWhether the serving mode was chosen by the owner rather than detected from the files of the deploy that went live. What lets the dashboard say which of the two it is showing.
nameWhat to call it, or null when it has none and the subdomain should be shown instead.
A label only. The site is reached by Subdomain whatever this says, which is why the dashboard shows the address underneath rather than replacing it: two sites are allowed the same name, and the name is not what anybody types into a browser.
openFeedback^-?(?:0|[1-9]\d*)$ · requiredThreads open on the site, the number on the Feedback tab.
passwordProtectedWhether visitors must enter a password. Only whether one is set is reported — the password itself is stored as a hash, so there is nothing to return.
passwordProtectionAvailableWhether this site's plan permits a password at all. Sent so the dashboard can show the control in a disabled state with a reason, rather than offering it and failing on submit.
planIdPlan whose limits apply.
primaryUrlThe URL to lead with: a hostname of the customer's own once one is serving, and Url otherwise.
Sent as its own field rather than by overwriting Url, because the two are not interchangeable and the subdomain does not stop mattering: it needs no DNS of anybody's and keeps working when a custom domain's records are changed or lapse, which makes it the address to fall back to when the other one is what is being diagnosed.
publicDocumentCountsWhether readers of this documents site see each document's views and downloads. Every plan may turn it on.
scheduledExpiryAvailableWhether this site's plan lets its owner schedule when it comes down. Sent so the dashboard can show the control disabled with a reason rather than offering it and failing on submit.
siteIdULID of the site.
spaModeWhether an unmatched path falls back to index.html.
statusWhether the site is serving, and if not, who switched it off — the SiteStatus name.
What the pause control reads, and what tells the three off-states apart for the customer. They need different words and different offers: their own pause has a button that undoes it, a suspension has support to contact, and being held for quota has an upgrade. One boolean could not say which.
statusChangedAtWhen the state last changed, or null if it never has.
subdomainIts subdomain.
subdomainChangesLeft^-?(?:0|[1-9]\d*)$ · requiredHow many more times the owner may change Subdomain, or null when the plan does not limit it. What the change-of-address control and its confirmation show.
trafficBreakdownAvailableWhether this site's plan includes top lists, the globe and filters on the traffic page. Sent so the page draws a locked card naming the tier instead of requesting a list and rendering a 403.
trafficDetailAvailableWhether this site's plan splits people from bots and AI and shows devices, browsers and campaigns.
urlIts public URL on the platform's own content domain.
SiteDomainResponse
bareDomainThe bare domain this www hostname sits directly on, or null when it is not a www
hostname or sits on something else.
What the dashboard needs to offer "send example.com here too": a bare domain cannot point at this
platform, so the customer redirects it to the www name at their DNS provider. Read from the
zone the nameserver lookup found when the domain was added, which is what makes
www.example.com.vn answer example.com.vn; a row added before that was recorded falls back
to the two-label case.
certificateReadyWhether the certificate has been issued, which is what says the DCV records are done rather than missing.
Sent because the provider stops returning those records the moment the certificate exists, including when it validated over HTTP without the customer adding anything. Without this the dashboard reads an empty list as "not issued yet" and the rows vanish from under somebody who is still copying them.
cnameTargetWhat the customer points their hostname at, once both validations pass. Served rather than hardcoded in the frontend for the reason every other piece of configuration is: a customer told the wrong target gets a hostname that validates and then never serves.
createdAtWhen the customer asked for the hostname.
dcvTxtNameName of the certificate validation TXT records, or null once none is needed.
dcvTxtValuesValues of the certificate validation TXT records, or empty once none is needed.
Several under one name: the certificate is issued as a pack and each member is validated separately, so the customer has more than one record to add and adding one of them satisfies nothing.
dnsProviderWho serves DNS for the hostname, as the lowercase name of DnsProvider, and therefore which order the dashboard has to ask for the records in.
hostnameThe hostname, normalized.
idULID of the domain row, used to remove or re-check it.
ownershipTxtNameName of the ownership TXT record, or null once it is no longer needed.
ownershipTxtValueValue of the ownership TXT record, or null for the same reason.
prevalidationUnavailableWhether the customer asked for the no-gap path and could not have it, because the certificate provider will not pre-validate a hostname whose zone it is already authoritative for — which is what DnsProvider reports when the customer's own DNS sits with the same provider.
Sent so the dashboard can say so. The override is right — the path they asked for cannot complete and the one they got does — but a customer who ticked the box to protect a live site and is told nothing will point their DNS here believing there is no gap, and learn otherwise from their own visitors.
statusWhere it is between being asked for and serving, as the lowercase name of SiteDomainStatus.
validationHow the certificate is being proven, as the lowercase name of CertificateValidation, and therefore how many records to show.
"http" is one CNAME and nothing else. "txt" is the no-gap path a customer asked for
because their hostname is already serving, and carries the record pairs above. Sent rather than
inferred from those pairs being empty, which is what an "http" row and a finished
"txt" row would otherwise look like alike.
verificationErrorsWhy the certificate provider has not activated the hostname, in its words, or empty when it has nothing to say.
verifiedAtWhen both validations first passed, or null while still pending.
SiteDomainsResponse
The site's custom domains, oldest first, excluding ones that were given up. Empty for a site with none, which is every site until somebody adds one.
SiteEnvResponse
allowedWhether the site may run functions now. False, the variables are kept but none reaches the edge, and none can be set.
maxTotalValueBytes^-?(?:0|[1-9]\d*)$ · requiredLargest total of a site's values, in UTF-8 bytes.
maxValueBytes^-?(?:0|[1-9]\d*)$ · requiredLargest value of one variable, in UTF-8 bytes.
maxVars^-?(?:0|[1-9]\d*)$ · requiredMost variables a site may hold.
valueBytes^-?(?:0|[1-9]\d*)$ · requiredThe values' total size, in UTF-8 bytes.
The variables, by name.
SiteFeedbackAuthor
nameThe name the site shows.
ownerWhether they own the site.
removedWhether they are no longer on the site's list, or their account is gone.
SiteFeedbackComment
Who wrote it.
bodyThe text, plain — the visitor's own words.
createdAtWhen it was written.
editedAtWhen its author last changed it, or null.
idComment id.
sourcePage when written on the site, Api when sent through the API.
SiteFeedbackPage
availableWhether the site's plan includes comments.
comments^-?(?:0|[1-9]\d*)$ · requiredComments the site holds, deleted ones not counted — what the plan's ceiling counts.
limit^-?(?:0|[1-9]\d*)$ · requiredThe plan's ceiling on comments per site.
open^-?(?:0|[1-9]\d*)$ · requiredThreads open on the site.
page^-?(?:0|[1-9]\d*)$ · requiredThe page returned, from 0.
pageSize^-?(?:0|[1-9]\d*)$ · requiredRows per page.
pathsEvery page that has a thread, for the page filter.
resolved^-?(?:0|[1-9]\d*)$ · requiredThreads resolved on the site.
The comments, newest first.
total^-?(?:0|[1-9]\d*)$ · requiredComments matching the filter.
SiteFeedbackPlace
kindtext for selected words, point for a pin.
prefixA little of what comes before them, for text.
quoteThe selected words, for text.
selectorThe CSS selector of the element.
snippetText near the pin, for point; may be empty.
suffixA little of what comes after them, for text.
SiteFeedbackRow
authorEmailTheir address, or null once their account is gone.
authorNameWho wrote it.
commentIdThe comment.
createdAtWhen it was written.
excerptThe text, cut at 280 characters.
onLiveVersionWhether the thread was opened on the version the site serves now.
pathThe page it is on.
replyWhether it replies in a thread rather than opening one.
resolvedWhether its thread is resolved.
threadIdIts thread, which the View link opens.
SiteFeedbackThread
Its comments, oldest first; deleted ones left out.
createdAtWhen it was opened.
idThread id, for replying and resolving.
outdatedWhether it was opened on an earlier version than the one the site serves now — the words it points at may have changed since.
pathThe page it is on: a path on the site, or a document's path in a documents site.
Where on the page.
resolvedAtWhen it was resolved, or null while open.
resolvedByWho resolved it, by name, or null while open.
urlThe link that opens the page at the thread.
SiteFeedbackThreadsPage
cursor^-?(?:0|[1-9]\d*)$ · requiredThe largest change value on the site at the moment of the read; send it as since to get only the
threads that changed after.
moreWhether another page follows.
page^-?(?:0|[1-9]\d*)$ · requiredThe page returned, from 0.
The threads, in the order they were opened.
SiteFolderNode
createdAtWhen the folder was created.
folderIdULID of the folder.
nameWhat the owner calls it.
parentIdThe folder it sits inside, or null when it sits at the root.
siteCount^-?(?:0|[1-9]\d*)$ · requiredSites filed directly in this folder, not counting those in folders inside it. Deleted sites are not counted — they are gone from the listing, so counting them would label an empty folder as holding something.
updatedAtWhen it was last renamed or moved.
SiteFolderResponse
The folder as it now stands.
SiteFoldersResponse
Every folder the account holds, by name.
maxDepth^-?(?:0|[1-9]\d*)$ · requiredHow deeply folders may nest. Sent for the same reason as MaxFolders: the drag target that would break this rule can be refused before the drop rather than after the request.
maxFolders^-?(?:0|[1-9]\d*)$ · requiredHow many folders this account may hold in total.
Sent so the dashboard can grey out "New folder" before somebody names one and is refused. A client that had to discover the limit by hitting it would have to discard what they typed.
SiteFormSummary
lastReceivedAtWhen the most recent one arrived.
nameThe name the form declared, from data-drop2run.
spam^-?(?:0|[1-9]\d*)$ · requiredHow many of those are marked spam, by us or by the owner.
submissions^-?(?:0|[1-9]\d*)$ · requiredHow many have arrived, spam included.
SiteFormsResponse
enabledWhether this site's switch is on, so the tab can say why nothing is arriving.
One row per form name, most recently used first.
monthlyAllowance^-?(?:0|[1-9]\d*)$ · requiredWhat the account's tier allows a month. Zero means forms are not part of it.
usedThisMonth^-?(?:0|[1-9]\d*)$ · requiredSubmissions the account has taken this calendar month, across every site it owns. The figure the allowance is measured against, which is why it is not the site's own count.
SitePauseResponse
ownerPausedWhether the owner has it switched off, whatever the status says.
siteIdULID of the site.
statusIts lifecycle state, one of SiteStatus as text.
statusChangedAtWhen the state last changed, or null if it never has.
subdomainThe subdomain it is addressed by, whether or not it is serving.
SiteProxyLogResponse
asOfWhen the entries were read, or null when they were not.
availableFalse when the log could not be read: no dataset configured, or Analytics Engine down.
Latest proxied requests, newest first.
SiteSettingsResponse
commentAudienceWho the owner chose may comment — Off, Invited or Anyone. The stored choice, which
takes effect only where the plan and the viewing mode allow it.
docsModeThe setting as it now stands.
expiresAtWhen the site is now scheduled to come down, or null when it has no schedule. Echoed because the request sends a string and this is the instant it parsed to.
expiryActionWhat that schedule will do. Reported even when ExpiresAt is null, where it is the choice a future date would inherit.
folderIdThe folder the site is now filed in, or null when it sits at the root. Echoed so a client that sent
"root" reads back the null it produced rather than the token it sent.
formsEnabledWhether this site accepts form submissions. The site's own switch, which the tier has to permit before the edge honours it — so a site on a tier without forms reports false here and cannot be set to true.
invitedOnlyWhether only the people on the site's list may now see it. Never true together with PasswordProtected.
liveWhether the hostname mapping was rewritten. False for a site that has never published, where the setting is stored and takes effect with its first deploy.
modeIsManualWhether the serving mode shown here was chosen by the owner rather than detected from the files.
Reported so the dashboard can say which it is. A control that renders a detected value identically to a chosen one tells the owner they picked something they never picked, and hides the one fact that explains why the mode changed after a deploy — or why it stopped changing.
nameThe name as it now stands, or null when the site has none and the dashboard should show its subdomain. Echoed back because cleaning can change what was sent.
passwordProtectedWhether the site now requires a password. The password itself is never returned — only the hash is stored, so there is nothing to return even if it were wanted.
publicDocumentCountsWhether readers see each document's views and downloads.
siteIdULID of the site.
spaModeThe setting as it now stands.
SiteSubdomainResponse
The names it used to answer on, newest first, each redirecting here.
siteIdULID of the site.
subdomainThe subdomain it answers on now.
subdomainChangesLeft^-?(?:0|[1-9]\d*)$ · requiredHow many more changes its plan allows, or null when it allows any number.
urlIts URL on the content domain.
SiteSummary
createdAtWhen the site was created.
docsModeWhether the site is served through the documents viewer. Here so a listing can label a folder of notes as one, rather than showing it as a static site that happens to answer oddly.
Unlike SiteDetail this listing does not carry whether the mode was chosen or detected: that
belongs beside the control that changes it, and there is no such control in a listing.
fileCount^-?(?:0|[1-9]\d*)$ · requiredFiles in the live deploy.
folderIdThe folder it is filed in, or null when it sits at the root of the listing.
On every row rather than only when a folder is being listed, because a search crosses folders and its results are flat: without this, a site found by searching would be found without any way to say where it lives, which is half an answer.
lastActiveAtWhen it last received a deploy.
liveDeployIdThe deploy being served, or null when nothing has gone live yet.
nameWhat to call it in a listing, or null to show the subdomain instead. What makes a list of sites readable: a generated subdomain says nothing about what a site holds.
primaryUrlThe URL to show: a hostname of the customer's own once one is serving, and Url otherwise.
The same field SiteDetail carries, and here for the same reason: a customer who has put their
own domain in front of a site does not think of it by the address this platform assigned, and a
listing that shows them one is a listing they have to translate. Kept beside Url
rather than replacing it, because the subdomain needs nobody's DNS and keeps answering when the
custom domain is what has gone wrong.
siteIdULID of the site.
spaModeWhether an unmatched path falls back to index.html.
statusWhether the site is serving, and if not, who switched it off — the SiteStatus name.
A listing has to carry it because a site that is off looks identical to one that is on from every other field here: it still has a live deploy, a size and a URL. Without this the dashboard would show a row that reads as healthy beside a hostname answering 404.
subdomainIts subdomain.
totalBytes^-?(?:0|[1-9]\d*)$ · requiredSize of the live deploy.
urlIts public URL on the platform's own content domain.
SiteTrafficDocument
downloads^-?(?:0|[1-9]\d*)$ · requiredLoads through the reader's Download button.
pathThe path with its leading slash, decoded. Recorded from requests and cut at 128 characters, so it is rendered as text rather than a link, like the top lists.
views^-?(?:0|[1-9]\d*)$ · requiredLoads of the file without the download flag.
SiteTrafficList
asOfWhen it was read from Analytics Engine, or null.
availableFalse when the list could not be read and nothing was kept.
breakdownDays^-?(?:0|[1-9]\d*)$ · requiredDays the list covers.
dimensionWhich list: page, referrer, country or notfound.
fromFirst instant the list covers — the breakdown window, not always the range.
Values, busiest first, or null when the list could not be read.
rangeThe range asked for.
sampledWhether any count is an estimate from sampled rows.
toEnd of the window, exclusive.
SiteTrafficListItem
count^-?(?:0|[1-9]\d*)$ · requiredPage views, or requests for broken links, the HTTP version and the cache.
valueThe path, host or country.
groupThe agent's group on the bot list — search, ai-search, ai-assistant,
ai-training or other — and null on every other list.
SiteTrafficOverview
asOfWhen the Analytics Engine figures were read, or null when none were.
availableFalse when Analytics Engine could not be read and nothing was kept.
breakdownDays^-?(?:0|[1-9]\d*)$ · requiredDays the lists, globe and status split cover — the range, capped at what Analytics Engine keeps.
bucketWidth of a chart point: hour, day or week.
days^-?(?:0|[1-9]\d*)$ · requiredIts length in days.
The documents table, by UTC day.
fromFirst instant of the range, UTC.
measuredSinceFirst day anything was rolled up for this site, or null.
rangeThe range as the page spells it: 24h, 12m, or {N}d.
sampledWhether any figure is an estimate from sampled rows.
The chart, or null when Analytics Engine could not be read.
seriesFromWhere the chart and tiles start: From, except on a filtered range longer than BreakdownDays, where only the breakdown window can be filtered.
speedAvailableFalse when the speed figures were asked for and could not be read, so a null Speed means "couldn't load" rather than "nothing measured".
splitSinceFirst whole day bots were counted apart from people and arrivals were recorded, or null when not yet. Before it, people include bots and visits are unknown; the page marks the day. Equal to MeasuredSince for a site that was split from its first day, which has no "before".
toEnd of the range, exclusive: the top of the next hour.
SiteUpstreamsResponse
The account's proxied requests this month against its plan.
limit^-?(?:0|[1-9]\d*)$ · requiredMost upstreams a site may declare.
proxyBlockedWhether the platform switched this site's proxy off (D17): every proxy route answers 404 until it is lifted, whatever the upstreams say.
The proxy routes the live version's _redirects declares; empty when it has none.
The site's upstreams, oldest first.
SiteViewerCounts
everyone^-?(?:0|[1-9]\d*)$ · requiredEverybody listed.
notOpened^-?(?:0|[1-9]\d*)$ · requiredThose who have not opened it yet.
opened^-?(?:0|[1-9]\d*)$ · requiredThose who have opened the site.
SiteViewerRow
emailThe address, as stored: trimmed and lower-cased.
firstOpenedAtWhen they first opened the site, or null if they have not.
invitedAtWhen the address was added.
lastEmailedAtWhen the invitation was last mailed, or null if it never was.
ownerWhether this is the address added for whoever switched the site to invite-only. It cannot be removed.
roleWhat they may do — only View is offered today.
statusOpened or NotOpened.
youWhether the address belongs to the person asking.
SiteViewersPage
availableWhether the plan offers invite-only sites at all. A list can outlive the plan that allowed it, and is still shown so it can be shortened; adding to it is refused.
How many people are in each status, ignoring the search and filter.
invitedOnlyWhether the site is currently open only to the people listed.
limit^-?(?:0|[1-9]\d*)$ · requiredThe most people this site's plan allows on the list, the owner included.
page^-?(?:0|[1-9]\d*)$ · requiredThe zero-based page returned.
pageSize^-?(?:0|[1-9]\d*)$ · requiredRows per page.
total^-?(?:0|[1-9]\d*)$ · requiredHow many rows match the search and filter, across every page.
The rows on this page: the owner's first, then the most recently added.
StartCliDeviceRequest
clientNameWhat the command line calls itself; becomes the token's name.
StartCliDeviceResponse
deviceCodeThe command line's own secret. Returned once; it is what collects the token.
expiresAtWhen both codes stop working.
intervalSeconds^-?(?:0|[1-9]\d*)$ · requiredHow long to wait between polls.
userCodeThe short code a person types, grouped for reading.
verificationUriWhere to go to approve, for somebody typing it by hand.
verificationUriCompleteThe same page with the code already filled in, for a clickable link.
StartEmailChangeRequest
emailThe address to move the account to.
codeA code from the authenticator app, which two-factor accounts may give instead.
currentPasswordThe account's password.
StartTwoFactorResponse
otpauthUriThe otpauth://totp/... URI to draw as a QR code.
secretThe same key in Base32, for typing into an app on a device with no camera.
SubdomainAvailabilityResponse
availableWhether this name could be used right now.
normalizedThe name as it would actually be stored, lowercase and trimmed. Null when the input failed format outright, in which case there was nothing to normalize.
reasonWhy not, using the same codes POST /sites would answer with. Null when
Available is true.
SubscriptionRow
cancelAtPeriodEndWhether it stops at the end of the current period.
currentPeriodEndWhen the paid period ends; null while paused.
graceUntilWhen the grace window on a failed payment runs out, or null.
intervalThe billing interval.
pausedAtWhen it was paused, or null.
pendingIntervalThe interval it switches to at the next renewal, or null.
pendingPlanIdThe plan it switches to at the next renewal, or null.
planIdThe plan currently paid for.
seats^-?(?:0|[1-9]\d*)$ · requiredHow many seats are being paid for; one on every tier not sold by the seat.
statusOne of the SubscriptionStatus names.
SupportReportContext
clientVersionThe client's own version.
codeThe error code the client was showing.
deployId^[0-9A-HJKMNP-TV-Za-…The deploy the client was working on.
siteId^[0-9A-HJKMNP-TV-Za-…The site the client was working on.
sourceWhich client: web, cli, mcp or link. web when absent.
traceIdThe API trace id the client was showing.
urlThe page the report was sent from.
TokenSummary
createdAtWhen it was issued.
expiresAtWhen it stops working on its own, or null.
idULID of the token.
lastUsedAtWhen a request last authenticated with it, or null if never.
nameWhat its owner called it.
prefixIts first characters, which is all there is to tell two rows apart by.
revokedAtWhen it was revoked, or null while it stands.
sourceHow it came to exist: Manual (this page), CommandLine (a sign-in on the person's machine)
or RemoteMcp (a hosted chat's connector, where revoking it disconnects that connector).
TrafficDocuments
fromFirst day counted.
Documents, most viewed first.
toLast day counted.
TrafficSeriesPoint
bytes^-?(?:0|[1-9]\d*)$ · requiredBytes sent, or null before measurement began.
pageviews^-?(?:0|[1-9]\d*)$ · requiredPage views, or null before measurement began.
requests^-?(?:0|[1-9]\d*)$ · requiredRequests, or null before measurement began.
startStart of the bucket, UTC.
visits^-?(?:0|[1-9]\d*)$ · requiredArrivals by people, or null before they were recorded.
TrafficSpeed
cacheHitRate^-?(?:0|[1-9]\d*)(?:… · requiredShare of requests the edge cache answered, between 0 and 1.
medianMs^-?(?:0|[1-9]\d*)$ · requiredMedian wait at the edge before the response existed, in milliseconds.
p95Ms^-?(?:0|[1-9]\d*)$ · required95th percentile of the same wait.
TrafficStatusSplit
s2xx^-?(?:0|[1-9]\d*)$ · requiredSuccessful.
s3xx^-?(?:0|[1-9]\d*)$ · requiredRedirected or not modified.
s4xx^-?(?:0|[1-9]\d*)$ · requiredClient errors, 404 included.
s5xx^-?(?:0|[1-9]\d*)$ · requiredServer errors.
TrafficTotals
bytes^-?(?:0|[1-9]\d*)$ · requiredBytes of body sent.
errorRate^-?(?:0|[1-9]\d*)(?:… · requiredShare of requests answered 4xx or 5xx, or null when it cannot be computed.
pageviews^-?(?:0|[1-9]\d*)$ · requiredPage views.
requests^-?(?:0|[1-9]\d*)$ · requiredRequests of every kind.
visits^-?(?:0|[1-9]\d*)$ · requiredPage views by people who arrived from another site or typed the address — not unique people — or null when arrivals were not recorded for the period.
TrustedDeviceResponse
createdAtWhen it was trusted.
currentWhether it is the browser asking.
expiresAtWhen it stops skipping one.
idIts id, which forgetting it names.
label"Chrome on macOS" — the raw User-Agent is not kept.
lastSeenAtWhen it last skipped a code.
TrustedDevicesResponse
The browsers, most recently used first.
TwoFactorChallengeResponse
challengeAlways two_factor; the page goes to /auth/2fa.
TwoFactorStatusResponse
enabledAtWhen a code first checked out and turned it on.
Accounts this person owns that require two-factor of their members. Non-empty means turning it off is refused, so the page disables the control and names the account to change first.
recoveryCodesLeft^-?(?:0|[1-9]\d*)$ · requiredHow many of the ten recovery codes are unused.
UpdateNameRequest
nameThe new display name, or null or blank to clear it.
UpdateSiteFolderRequest
nameA new name, or null to leave it alone.
parentIdWhere to move it: a folder id, or "root" to move it to the top level. Null leaves it where it
is — see string SiteFolderAccess.RootToken for why moving to the root needs a token of its
own rather than a null.
UpdateSiteSettingsRequest
commentAudienceWho may comment on the site's pages: Off or Invited, in any case. Null leaves it alone.
Invited is refused on a plan without comments (string Errors.FeedbackUnavailable);
Off never is. It is stored whatever the viewing mode, and only takes effect while the site is
invite-only — switching the site to public keeps the choice for when it comes back.
Anyone is not accepted yet (docs/IMPLEMENTATION-PLAN.md §16.7 S11).
docsModeWhether the site is served through the documents viewer instead of as a plain static site. Null leaves the setting alone.
Sending either this or SpaMode tells the server the owner has chosen, and detection stops
deciding for this site from then on. The two cannot both be on, so a client switching between modes
sends both fields rather than only the one it is enabling.
expiresAtWhen the site should come down, as an ISO 8601 instant — or an empty string to cancel a schedule it already has.
A string rather than a DateTimeOffset?, and the reason is the same one Name
and Password give: null has to keep meaning "not sent", so there has to be some
other value that means "clear it". An empty string is that value for all three.
expiryActionWhat the expiry does when it falls due — Pause or Delete, defaulting to Pause
for a date an owner sets.
Only read when a date is being set. Sending it alone is refused rather than stored, because an action with no date is a decision about an event that will not happen, and storing it would answer 200 to a request that changed nothing observable.
folderIdWhich of the account's folders to file the site in, or "root" to take it back out of every
folder. Null leaves it where it is.
A literal token for the root rather than a null, for the reason the other clearable fields here take an empty string: null has to keep meaning "not sent". Unlike them it is a word rather than an empty string, because the same token spells the root in the listing's query parameter and an empty query parameter already means "absent" — see string SiteFolderAccess.RootToken.
Nothing about serving depends on it, so unlike the settings around it this triggers no KV write.
formsEnabledWhether this site's hostnames accept form submissions. Null leaves the setting alone.
Turning it on is refused when the account's tier does not include forms (string Errors.FormsNotAvailable); turning it off is always allowed, so a site whose tier changed underneath it is never stranded switched on.
This switches the endpoint on for the site. Which forms exist and what they are called is not a
setting at all — it comes from data-drop2run in the HTML (docs/IMPLEMENTATION-PLAN.md §16.2.1 F7).
invitedOnlyWhether only the people on the site's list may see it, each signed in with their own account. Null leaves the setting alone.
Turning it on clears any password, since the two exclude each other, and adds the caller's own address to the list so they are not locked out; sending it together with a new password is refused. Turning it off is always allowed. The list is kept across both, and either change signs every invited visitor out — those still on the list are let back in without being asked anything.
nameWhat to call the site in the dashboard, or an empty string to clear it and fall back to the subdomain. Null leaves it alone.
Cleaned by SiteNames rather than validated: a name is a label, so there is no shape to reject — only invisible characters to strip and a length to cap. A name that cleans away to nothing is stored as null, which is the same as having cleared it.
passwordA new access password for the site, or an empty string to remove the gate and make it public again. Null leaves the current setting alone.
The three states are deliberately carried by one nullable string rather than a string plus a boolean.
With two fields a client could send a password and private: false together, and there would be
no correct interpretation — the endpoint would have to guess or refuse a body that looks valid.
Never echoed back. The response reports only whether a gate is now in place.
publicDocumentCountsWhether readers of the site see each document's views and downloads in the reader's toolbar. Null leaves it alone. Allowed on every plan. The counts are of file loads, not of people, and appear within about an hour of switching on; switching off takes up to five minutes to reach every reader.
spaModeWhether an unmatched path should fall back to index.html, for a site whose routing happens in
the browser. Null leaves the setting alone, and a body where every field is null is refused.
UpdateSiteUpstreamRequest
methodsThe methods to allow from now on; unchanged when left out.
removeHeadersNames of headers to drop.
Headers to add or replace, values in plain text — sealed on arrival.
UploadBatch
The files, in the order their bytes must follow the layout.
tokenBearer token authorising exactly these files.
UploadTarget
pathNormalized path, which is also what the manifest records.
sha256Digest signed into Token, echoed back because the client needs it to name the file it is sending. It is the same value the client put in the manifest; returning it saves the client from keeping its own manifest indexed by path just to find it again.
tokenBearer token authorising exactly this object. Signed by the control plane and verified by the upload Worker, which refuses a second write of the same key without touching R2.
UpstreamHeaderInput
nameHeader name, any case.
valueThe value, sealed on arrival and never shown back.
UpstreamHeaderView
last4The value's last four characters, or empty for a short value.
nameHeader name, lowercase.
UpstreamView
blockedWhether the platform blocked this origin for every site (D17): calls to it answer 502 until the block is lifted.
createdAtWhen it was declared.
Header names and the last four characters of each value.
idUpstream id.
methodsMethods visitors may send, GET implying HEAD.
originhttps://host.
updatedAtWhen it last changed.
UsageResponse
bytes^-?(?:0|[1-9]\d*)$ · requiredWhat the account is holding on storage — every deploy of every site whose files have not been
removed, not just the version currently serving. The same total prepare weighs against
long? PlanResponse.MaxAccountBytes, so the page can say how much room is left and be right.
countedSites^-?(?:0|[1-9]\d*)$ · requiredHow many of those the site allowance is measured against: the ones the account holds, which is
Active plus Paused. CreateSite and ClaimSites refuse against exactly
this set. A site an administrator suspended or the quota job cut is excluded from both.
Sent beside Sites rather than replacing it because a page needs both: the total explains why the list can be longer than the allowance, and this one says whether anything is refused. A dashboard given only the total told an account holding sites the platform had switched off that it was at a limit it was not at.
extraAllowanceUsedWhether this account has already been let past its monthly budget once this month.
filesResetAtWhen the monthly figure returns to zero. Sent so the page can name a date rather than say "next month", which is a different day depending on when it is read.
filesThisMonth^-?(?:0|[1-9]\d*)$ · requiredFiles published this calendar month, counted the way the budget counts them: one per piece of content that was new, plus one per deploy.
filesThisMonthLimit^-?(?:0|[1-9]\d*)$ · requiredWhat the tier allows in a month, or null when the tier is not bounded by month.
formSubmissionsThisMonth^-?(?:0|[1-9]\d*)$ · requiredForm submissions the account has taken this calendar month, across every site it owns, read from the counter the ingest path adds to. Measured against int PlanResponse.MaxFormSubmissionsPerMonth and reset on FilesResetAt, which is the same calendar month boundary.
membersOverSeats^-?(?:0|[1-9]\d*)$ · requiredPeople on the account past the seats it pays for — zero on every account in good standing. Non-zero means a team stopped paying, and that many people are removed, the most recently added first, when DateTimeOffset? MeResponse.OverLimitUntil passes. Sent as a count rather than as the member total so the page does not have to know where the seat ceiling sits.
proxyRequestsThisMonth^-?(?:0|[1-9]\d*)$ · requiredRequests the account's sites sent through the API proxy this calendar month, read from the counter the monthly hold is decided on, so up to about an hour and a half behind. Measured against int PlanResponse.MaxProxyRequestsPerMonth; zero where the deployment does not serve the proxy.
proxySuspendedWhether this month's proxy allowance is spent and every proxy route of the account answers 429.
sites^-?(?:0|[1-9]\d*)$ · requiredNumber of non-deleted sites the user owns, whatever state they are in. This is how many rows the
site list shows, and it is not the figure the plan's site allowance bounds — read
countedSites for that.
VerifyEmailRequest
tokenThe token the mailed link carried.