# Server.Express API - [Introduction](https://docs.server.express/introduction.md): What the Server.Express API covers, where it lives, and what it can't do yet. Start here before you write any client code. - [Quickstart](https://docs.server.express/quickstart.md): Create an API token, make your first authenticated call, and read the response envelope. About two minutes, start to finish. - [Authentication](https://docs.server.express/authentication.md): Sessions versus API tokens, the token format, all 14 scopes and what each one grants, expiry, revoking, and which endpoints accept a token at all. - [Errors and rate limits](https://docs.server.express/errors-and-rate-limits.md): The response envelope, every status code the public API returns, the per-endpoint rate limits, and how repeated failed authentication gets an IP blocked. - [Servers](https://docs.server.express/guides/servers.md): List cloud and dedicated servers, read status and metrics, and drive power, rescue, snapshots, reinstall and cancellation from your own scripts. - [Billing and tickets](https://docs.server.express/guides/billing-and-tickets.md): Read invoices, download PDFs, pay from account credit, merge open invoices, and open or reply to support tickets, with attachments, from your monitoring and accounting jobs. - [Reselling](https://docs.server.express/guides/reselling.md): Read live dedicated, cloud and shared hosting stock at your own rate, then place real orders from your own system. One catalogue call, three order calls, and the same token that manages your servers. - [API reference](https://docs.server.express/api-reference/introduction.md): Base URL, authentication and the response envelope for every public Server.Express endpoint. The reference pages are generated from the OpenAPI spec. - [Finish sign-in with an authenticator or backup code](https://docs.server.express/api-reference/auth/finish-sign-in-with-an-authenticator-or-backup-code.md): Completes a sign-in that stopped at the second factor. Takes a six-digit TOTP code or a 10-character backup code (with or without the hyphen) — the server tells them apart by length. A TOTP code can't be replayed and a backup code is spent on use; when one is, `backupCodesRemaining` tells you how ma… - [Get passkey assertion options for sign-in](https://docs.server.express/api-reference/auth/get-passkey-assertion-options-for-sign-in.md): First half of the passkey second factor. Exchanges the pre-auth token for WebAuthn authentication options (from @simplewebauthn/server) covering every passkey on the account, and stores the challenge server-side for /v1/auth/2fa/verify. Pass `data` straight to `startAuthentication()`. Not rate-limit… - [Get two-factor status](https://docs.server.express/api-reference/auth/get-two-factor-status.md): Which second factors the signed-in account has. `required` is true when a password alone no longer signs in. `enrolmentPending` means setup was started but never confirmed — that doesn't count as a factor. - [Confirm authenticator-app setup](https://docs.server.express/api-reference/auth/confirm-authenticator-app-setup.md): Checks a code against the pending secret and switches the authenticator on. Returns 10 fresh backup codes and clears any left from a previous enrolment. The codes are shown once — no endpoint returns them again. A wrong code is 400 (usually a phone clock that's drifted). 409 if already confirmed. Wr… - [Start authenticator-app setup](https://docs.server.express/api-reference/auth/start-authenticator-app-setup.md): Generates a TOTP secret and returns it with an `otpauth://` URI for the QR code. Nothing is active until PUT confirms a code. Calling this again replaces an unconfirmed enrolment. Returns 409 if an authenticator is already confirmed, and 503 if the server has no encryption key to store the secret wi… - [Turn off the authenticator app](https://docs.server.express/api-reference/auth/turn-off-the-authenticator-app.md): Removes the authenticator and every backup code. Costs a fresh proof: either the account password or a current code (TOTP or backup). The code path exists for Google/Discord accounts, which have a random password nobody knows. If both are sent, only the password is checked. A wrong proof is 403. Pas… - [Issue a new set of backup codes](https://docs.server.express/api-reference/auth/issue-a-new-set-of-backup-codes.md): Replaces every backup code with 10 new ones. Requires a live authenticator code — a backup code won't do, so one leaked code plus a stolen session can't mint more. A wrong code is 403. Rate-limited to 10 requests per 15 minutes per IP. Writes a REGENERATE_BACKUP_CODES audit entry. - [Finish sign-in with a passkey](https://docs.server.express/api-reference/auth/finish-sign-in-with-a-passkey.md): Second half of the passkey second factor. Verifies the WebAuthn assertion against the challenge from /v1/auth/2fa/options (single use), bumps the passkey's counter and issues the session. A failed ceremony is 403, not 401. An expired pre-auth token, a missing challenge or a passkey that isn't on thi… - [Email a password reset link](https://docs.server.express/api-reference/auth/email-a-password-reset-link.md): Always answers 200 once the captcha passes, whether or not the address has an account. If it does, a one-hour reset link is emailed (or, with no mail provider configured, logged on dev only). The link dies as soon as the password changes. Requires a Cloudflare Turnstile token. Rate-limited to 10 req… - [Sign in with email and password](https://docs.server.express/api-reference/auth/sign-in-with-email-and-password.md): Checks the password and either issues a session or, when the account has a second factor (a passkey or a confirmed authenticator app), returns a short-lived pre-auth token instead. Pass that token to /v1/auth/2fa/code or /v1/auth/2fa/options + /v1/auth/2fa/verify to finish signing in. Rate-limited t… - [Sign out](https://docs.server.express/api-reference/auth/sign-out.md): Revokes refresh tokens. The access JWT can't be revoked and simply expires within 15 minutes. Send `refreshToken` to end just this device; send `everywhere: true`, or no refresh token at all, to end every session on the account. The body is optional — a missing or non-JSON body revokes everything. A… - [Get the signed-in user](https://docs.server.express/api-reference/auth/get-the-signed-in-user.md): The account behind the session token. Browser sessions only — API tokens are rejected with 401 (use /v1/auth/whoami for those). Note `role` is lowercase here, unlike the session payloads. - [Start Discord sign-in or account linking](https://docs.server.express/api-reference/auth/start-discord-sign-in-or-account-linking.md): Redirects the browser to Discord's consent screen (scopes `identify email`). With `link=1` the callback goes to the client area's link page (/client/link-callback/discord) instead of the sign-in callback. Discord sign-in only works for an account that's already linked. - [Finish an OAuth sign-in](https://docs.server.express/api-reference/auth/finish-an-oauth-sign-in.md): Called by the portal's OAuth callback page. Verifies the signed `state`, swaps the provider's `code` for an access token, reads the user's identity and signs them in. Google creates an account on first sign-in (with the email already confirmed); Discord and Telegram only match an account that's alre… - [Start Google sign-in](https://docs.server.express/api-reference/auth/start-google-sign-in.md): Redirects the browser to Google's consent screen (scopes `openid email profile`). The `state` is a signed 10-minute ticket. Google sends the user back to the portal at /auth/oauth-callback/google, which then calls /v1/auth/oauth/exchange. - [Start Telegram sign-in or account linking](https://docs.server.express/api-reference/auth/start-telegram-sign-in-or-account-linking.md): Redirects the browser to Telegram's OpenID Connect flow (scopes `openid profile`). With `link=1` the callback goes to /client/link-callback/telegram instead of the sign-in callback. Telegram sign-in only works for an account that's already linked. - [Trade a refresh token for a new session](https://docs.server.express/api-reference/auth/trade-a-refresh-token-for-a-new-session.md): Rotates the refresh token: the one you send is dead the moment this returns, and you get a fresh access token (15-minute JWT) and refresh token (30 days, sliding). Replaying a spent token more than 15 seconds after it was rotated revokes every session on the account. Every failure is the same flat 4… - [Create an account](https://docs.server.express/api-reference/auth/create-an-account.md): Creates a client account with a billing profile and signs it in straight away (201 with a session). A confirmation email goes out in the background; a mail failure doesn't fail the signup. Throwaway email domains are refused. Countries under sanctions or compliance restrictions get 403. Requires a C… - [Send the confirmation email again](https://docs.server.express/api-reference/auth/send-the-confirmation-email-again.md): Sends a fresh confirmation link to the signed-in user. Does nothing if the address is already confirmed. `sent` is false if the mailer couldn't deliver. Limited to 3 requests per 15 minutes, keyed on the Authorization header rather than the IP. - [Set a new password from a reset link](https://docs.server.express/api-reference/auth/set-a-new-password-from-a-reset-link.md): Redeems the token from the forgot-password email. The link is single-use — it carries a fingerprint of the old password hash, so once any new password is set it (and every older link) stops working. Revokes every refresh session on the account; existing access tokens expire on their own within 15 mi… - [Sign in from the Telegram Mini App](https://docs.server.express/api-reference/auth/sign-in-from-the-telegram-mini-app.md): Exchanges Telegram WebApp `initData` for a session. The HMAC is checked against the bot token and `auth_date` must be under an hour old. Only works for a Telegram account already linked in Settings — this never creates an account. If the account has a second factor, returns a pre-auth token instead… - [Confirm an email address](https://docs.server.express/api-reference/auth/confirm-an-email-address.md): Redeems the 24-hour link from the confirmation email. Deliberately unauthenticated so the link works on any device. Every failure returns the same 400 message. Redeeming a link for an already-confirmed address succeeds with `alreadyVerified: true`. Rate-limited to 10 requests per 15 minutes per IP. - [Describe the current credential and its scopes](https://docs.server.express/api-reference/auth/describe-the-current-credential-and-its-scopes.md): Who this credential is and what it may do. Accepts a browser session or an API token, with no particular scope required. A session reports every scope; a token reports its own. `admin` is true only for an ADMIN session, because admin routes never accept API tokens. This is informational — every rout… - [Order one or more cloud servers](https://docs.server.express/api-reference/cloud/order-one-or-more-cloud-servers.md): Reserves up to 10 VDS on one plan: a PENDING service per server and a single UNPAID invoice covering the lot. Nothing is cloned on Proxmox until that invoice settles. Prices, term discounts and add-ons are re-derived server-side from ids; the caller never sends an amount. Requires a complete billing… - [List cloud plans priced for you](https://docs.server.express/api-reference/cloud/list-cloud-plans-priced-for-you.md): Active VDS plans, priced in the customer's currency. An explicit `currency` wins; otherwise the profile's preferred currency is used, falling back to GBP. Without `nodeGroup` only plans sold everywhere are listed; with it, plans pinned to that hardware group are included too. - [List your cloud servers](https://docs.server.express/api-reference/cloud/list-your-cloud-servers.md): Every CLOUD service you own or that's shared with you through a team, newest first. Power state comes from the poller (`powerState`, `powerCheckedAt`) — the list never calls Proxmox. Without `limit` every server is returned and there's no `nextCursor`; with it, results are cursor-paged. - [List VDS add-ons](https://docs.server.express/api-reference/cloud/list-vds-add-ons.md): Optional extras a VDS can be bought with — every active AddonProduct whose `appliesTo` includes CLOUD, ordered by name. `currency` filters rather than converts: an add-on is only offered in the currency it's priced in, because renewals bill `AddonProduct.price` unconverted. Prices are monthly minor… - [List one-click apps](https://docs.server.express/api-reference/cloud/list-one-click-apps.md): Active one-click apps a customer can deploy instead of a bare OS, ordered by sortOrder then name. Generated secrets are never included in `fields`. No authentication. - [List billing terms](https://docs.server.express/api-reference/cloud/list-billing-terms.md): The billing terms a VDS can be bought on and the discount each one carries (in basis points). This is the same ladder checkout and invoices use. No authentication. - [List deploy locations](https://docs.server.express/api-reference/cloud/list-deploy-locations.md): Active locations a VDS can be deployed to, featured first, then by city. Use `slug` as `?location=` elsewhere. No authentication. - [List hardware groups in a location](https://docs.server.express/api-reference/cloud/list-hardware-groups-in-a-location.md): Hardware groups with at least one active Proxmox node in the given location, ordered by name. `planCount` counts the active plans that can be sold on each group (plans pinned to it plus plans sold everywhere), so a picker can hide empty groups. No authentication. - [List VDS plans](https://docs.server.express/api-reference/cloud/list-vds-plans.md): The public plan catalogue, priced in the requested currency — a hand-set price when one exists, otherwise FX-converted from the plan's base price and flagged `priceEstimated`. Without `nodeGroup` only plans sold everywhere are returned; with it, plans pinned to that group are included too. No authen… - [List OS templates](https://docs.server.express/api-reference/cloud/list-os-templates.md): Active OS images a customer can deploy, ordered by sortOrder then name. Any template works on any plan. No authentication. - [Get a cloud server](https://docs.server.express/api-reference/cloud/get-a-cloud-server.md): Header info for one VDS: the legacy flat fields, any long-running task in flight (so a reloaded page picks its progress back up), the shared `machine` shape, and your `role` on it. Power in `machine` is the poller's reading, not a live call. Owners and team members with any role can read it. - [List a server's activity](https://docs.server.express/api-reference/cloud/list-a-servers-activity.md): Recent audit events for this VM, newest first — power actions, reinstalls, cancellations, rDNS edits, credential reveals and app installs. Staff (`ADMIN_*`) actions are excluded, no user id or IP is returned, and metadata is limited to an allowlist of keys (action, os, osName, ip, serviceType, hostn… - [List installed catalogue apps](https://docs.server.express/api-reference/cloud/list-installed-catalogue-apps.md): Catalogue apps installed on this server (newest first, removed ones kept as history), the installable catalogue, and the server's size so a picker can explain why an app won't fit. Session auth only; any team role can read it. - [Install a catalogue app](https://docs.server.express/api-reference/cloud/install-a-catalogue-app.md): Queues a one-click app install and returns at once; poll GET /v1/cloud/{id}/app-installs for its state. Inputs are validated against the app's field schema and generated secrets are minted server-side. Session auth only; needs the operate role. 403 while PENDING/SUSPENDED. 409 when busy, not yet pro… - [Uninstall a catalogue app](https://docs.server.express/api-reference/cloud/uninstall-a-catalogue-app.md): Stops the app on the server and removes its directory. Docker volumes (the app's data) survive unless `purge=1`. If the VM can't be reached the install is still marked REMOVED and `warning` says so. Session auth only; needs the operate role. 403 while PENDING/SUSPENDED; 409 if already removed. Write… - [List Docker stacks](https://docs.server.express/api-reference/cloud/list-docker-stacks.md): Docker Compose stacks under /opt/serverexpress on the VM, read live through the guest agent on every call. Stacks that came from the catalogue carry `appSlug`, `appName` and `installStatus`. Session auth only; any team role can read it. 409 if the server isn't provisioned yet, 502 if Docker on the V… - [Create and start a Docker stack](https://docs.server.express/api-reference/cloud/create-and-start-a-docker-stack.md): Writes a compose file (and `.env` when `env` is given) to /opt/serverexpress/ on the VM and runs `docker compose up -d`. Send raw `compose` text, or the simple form (`image`, `ports`, `volumes`, `env`) and we'll build the compose file. Session auth only; needs the operate role. 409 if the stac… - [Get Docker stack logs](https://docs.server.express/api-reference/cloud/get-docker-stack-logs.md): Recent `docker compose logs` output for one stack (captured buffer, not a stream; capped at 200 KB). Session auth only; any team role can read it. - [Run a Docker stack action](https://docs.server.express/api-reference/cloud/run-a-docker-stack-action.md): Runs `up`, `down`, `restart` or `pull` on one stack and returns the last 8000 characters of output. Session auth only; needs the operate role. 404 if no such stack exists on the server. - [Remove a Docker stack](https://docs.server.express/api-reference/cloud/remove-a-docker-stack.md): Destructive: runs `docker compose down --volumes`, dropping the stack's named volumes, then deletes its directory. Session auth only; needs the operate role. 404 if no such stack exists. - [Cancel a cloud server](https://docs.server.express/api-reference/cloud/cancel-a-cloud-server.md): Owner only. Without `immediate` the service becomes CANCELLED and is terminated (VM deleted) by the billing lifecycle at `nextDueDate`. With `immediate: true` the VM is deleted and its IPs released now, and the service becomes TERMINATED. Either way active add-ons are cancelled, the reason and time… - [Open a VNC console](https://docs.server.express/api-reference/cloud/open-a-vnc-console.md): Mints a short-lived console handle for this VM. Connect a noVNC client (WebSocket) to `path` on the API origin within `expiresInMs` and authenticate with `password` — the relay holds the hypervisor side, so no Proxmox address or credential is exposed. Proxmox expires the VNC password about 30 second… - [Get the VM's CPU model](https://docs.server.express/api-reference/cloud/get-the-vms-cpu-model.md): Reads the VM config live from Proxmox. `selected` is the saved (pending) model, `running` is what the running machine has; `rebootRequired` is true when they differ. `options` lists every model you may choose. Any team role can read it. - [Set the VM's CPU model](https://docs.server.express/api-reference/cloud/set-the-vms-cpu-model.md): Writes the CPU model into the VM config. It takes effect on the next full stop and start — a reboot from inside the guest won't pick it up; `rebootRequired` is true when the VM is running now. Needs the operate role; blocked while PENDING/SUSPENDED (403). Writes a `SET_CLOUD_CPU_TYPE` audit entry. - [Reveal login credentials](https://docs.server.express/api-reference/cloud/reveal-login-credentials.md): Decrypts and returns the cloud-init admin password with the login user and IP. Owner only — team members get 404 and should use SSH keys. `username` is Administrator on Windows templates and root elsewhere; `ssh` is false on Windows. `password` is null when none was stored. Blocked while a rebuild i… - [Get network details](https://docs.server.express/api-reference/cloud/get-network-details.md): The VM's primary IPv4, extra IPv4s and IPv6 address with gateways and netmasks, plus the customer's routed IPv6 prefix. `ptr` is a live reverse-DNS lookup (1.5 s timeout per address, null when none or slow). Any team role can read it. - [Set reverse DNS](https://docs.server.express/api-reference/cloud/set-reverse-dns.md): Sets the PTR record for one of this VM's addresses — its primary or extra IPv4s, or any address inside the customer's IPv6 prefix (compressed before saving). Needs the operate role; session auth only. Blocked while PENDING/SUSPENDED (403) or busy (409); 403 if the IP isn't this server's; 404 if the… - [List plans this server can move to](https://docs.server.express/api-reference/cloud/list-plans-this-server-can-move-to.md): The plans sold on this server's own hardware, each priced in the service's currency (reseller discount applied) and quoted against what the service pays today, with the disk consequence of moving. Plans that can't be priced in the service currency are left out. `pending` is an unpaid upgrade, if any… - [Change plan](https://docs.server.express/api-reference/cloud/change-plan.md): Moves the server to another plan on the same hardware. Upgrades with something to pay raise an UNPAID invoice (due in 7 days) for the prorated difference and land when it's paid — `applied: false`. Downgrades, sideways moves and zero-cost upgrades apply immediately and pay unused value back as extra… - [Power a server](https://docs.server.express/api-reference/cloud/power-a-server.md): Runs a power verb on this service's VM without needing its hypervisor vmid. `shutdown` is a graceful ACPI request, `stop` pulls the plug, `reset` is a hard reboot. Needs the operate role (owner, ADMIN or OPERATOR). Blocked while the service is PENDING or SUSPENDED (403) and while a rebuild or other… - [Reinstall the OS](https://docs.server.express/api-reference/cloud/reinstall-the-os.md): Wipes the VM and redeploys it from the chosen OS template. The old VM is destroyed and a fresh clone made; the reserved IP is kept and a new root password is set. Returns 202 with a task id straight away — the rebuild takes minutes, and every other control on the server is refused until it lands. Ne… - [Get the raw hypervisor VM record](https://docs.server.express/api-reference/cloud/get-the-raw-hypervisor-vm-record.md): Calls Proxmox live and returns this service's VM as the hypervisor reports it — an array with zero or one entry (never other customers' VMs on the same host). Returns 503 if the server hasn't been placed on a node yet. - [List snapshots](https://docs.server.express/api-reference/cloud/list-snapshots.md): Snapshots on this VM, newest first, read live from the hypervisor, plus the per-server cap (3 unless configured otherwise). Readable in any service state by any team role. A failed read is a 502, never an empty list. - [Take a snapshot](https://docs.server.express/api-reference/cloud/take-a-snapshot.md): Starts a disk-only snapshot (no RAM state) as a background task and returns 202 with the task id. Needs the operate role and an ACTIVE or CANCELLED service (403 otherwise). 409 when a task is already running, the cap is reached (the body's `data` carries `limit` and `used`), or the name is taken. Wr… - [Roll back to a snapshot](https://docs.server.express/api-reference/cloud/roll-back-to-a-snapshot.md): Destructive: throws away everything written since the snapshot. Runs as a background task — a running VM is stopped, the disk rolled back, and the VM started again — and returns 202 with the task id. The body must say `{ "action": "rollback" }`. Needs the operate role and an ACTIVE or CANCELLED serv… - [Delete a snapshot](https://docs.server.express/api-reference/cloud/delete-a-snapshot.md): Deletes the snapshot as a background task (merging it away can take minutes on a big disk) and returns 202 with the task id. Needs the operate role and an ACTIVE or CANCELLED service. 404 if the snapshot doesn't exist; 409 if a task is already running. Writes a `CLOUD_SNAPSHOT_DELETE` audit entry on… - [Get usage statistics](https://docs.server.express/api-reference/cloud/get-usage-statistics.md): Live VM state plus the Proxmox RRD usage series for the chosen window, with a rough CO₂e estimate (per-vCPU power model × PUE 1.2 × the node country's grid intensity — not billing-grade). Empty RRD slots are dropped. Owners, any team role and staff can read it. - [Get resource upgrade options](https://docs.server.express/api-reference/cloud/get-resource-upgrade-options.md): The server's live size, the extras it already pays for, any unpaid upgrade, and this hardware's per-unit monthly prices and ceilings. `pricing` is null when the hardware sells no upgrades. Prices are in the node group's `upgradeCurrency` (converted to the service currency at order time). Session aut… - [Order a resource upgrade](https://docs.server.express/api-reference/cloud/order-a-resource-upgrade.md): Orders extra cores, RAM, disk or IPv4s. Send the absolute target extras (not a delta), so a retried request lands on the same size. Raises an UNPAID invoice (due in 7 days) for the monthly difference prorated over the days left in the period; the resources land when it's paid. Values are floored to… - [Check web shell availability](https://docs.server.express/api-reference/cloud/check-web-shell-availability.md): Whether a browser shell can be opened on this server and what second factor the account has. Session auth only; needs the operate role. - [Open a web shell session](https://docs.server.express/api-reference/cloud/open-a-web-shell-session.md): Verifies a second-factor code (TOTP or backup code) — required every time — checks the guest agent is reachable, starts a pty on the VM and mints a 30-minute session. Connect a WebSocket to `path` on the API origin. Linux only. Session auth only; needs the operate role. 403 while PENDING/SUSPENDED;… - [Get VM status by vmid](https://docs.server.express/api-reference/cloud/get-vm-status-by-vmid.md): Live Proxmox status for this service's VM. `vmid` must be the service's own vmid; anything else gets the same 404 as a missing server, so vmids can't be enumerated. Prefer GET /v1/cloud/{id}, which doesn't need the vmid. - [Power a VM by vmid](https://docs.server.express/api-reference/cloud/power-a-vm-by-vmid.md): Legacy form of POST /v1/cloud/{id}/power for API callers that already hold the vmid. Same body, rules, side effects and responses; additionally the vmid must be the service's own (404 otherwise). - [Destroy the VM](https://docs.server.express/api-reference/cloud/destroy-the-vm.md): Deletes the VM on the hypervisor and returns its primary IPv4, any extra IPv4s and its IPv6 address to the pools. The Service row and its billing are left as they are — use POST /v1/cloud/{id}/cancel to end the contract. Owner only (team members get 404), session auth only (API tokens are not accept… - [Show linked Discord and Telegram accounts](https://docs.server.express/api-reference/account/show-linked-discord-and-telegram-accounts.md) - [Unlink a Discord or Telegram account](https://docs.server.express/api-reference/account/unlink-a-discord-or-telegram-account.md): Clears the provider id and username from the profile and writes an UNLINK_DISCORD / UNLINK_TELEGRAM audit log entry. - [Finish linking a Discord or Telegram account](https://docs.server.express/api-reference/account/finish-linking-a-discord-or-telegram-account.md): Completes the OAuth round trip: verifies the signed `state` (it must name the same provider and be a link ticket), exchanges `code` with the provider, and stores the provider's user id and username on the profile. Rejects with 409 if that provider account is already linked to another user. Writes a… - [Change your password](https://docs.server.express/api-reference/account/change-your-password.md): Verifies the current password, then stores the new one. Writes a PASSWORD_CHANGE audit log entry. A wrong current password returns 401. - [Your account and billing profile](https://docs.server.express/api-reference/account/your-account-and-billing-profile.md): Name, email, role and billing profile, plus the currencies you can choose to be billed in. - [Update your name and billing profile](https://docs.server.express/api-reference/account/update-your-name-and-billing-profile.md): Partial update; only allow-listed fields are read and anything else is ignored. Text fields are trimmed and capped at 255 characters; null or "" clears them. A new `vatNumber` is checked against VIES and `vatValid` is set from the result — it can't be sent. A body that sets `country` to US, CA or AU… - [Get auto-pay state](https://docs.server.express/api-reference/account/get-auto-pay-state.md): The caller's saved-card summary, auto-pay toggle and account credit balance (minor units). - [Turn auto-pay on or off](https://docs.server.express/api-reference/account/turn-auto-pay-on-or-off.md): Sets whether renewals auto-charge the saved card. Creates the profile row if it doesn't exist yet. - [Remove the saved card](https://docs.server.express/api-reference/account/remove-the-saved-card.md): Forgets the saved card so renewals stop auto-charging. The Stripe payment-method detach is best-effort; clearing our record always happens. Writes a SAVED_CARD_REMOVED audit entry. - [Get account settings](https://docs.server.express/api-reference/account/get-account-settings.md): Profile, address, VAT and linked chat accounts, plus the currencies the caller may choose. - [Update account settings](https://docs.server.express/api-reference/account/update-account-settings.md): Allow-listed partial update; unknown keys are dropped. Text fields are trimmed (max 255) and `null`/"" clears them. Sending `vatNumber` triggers a VIES lookup that sets `vatValid` server-side. A US, CA or AU country requires `region`. Writes an UPDATE_USER_SETTINGS audit entry listing the changed fi… - [Preview what a coupon is worth on a basket](https://docs.server.express/api-reference/coupons/preview-what-a-coupon-is-worth-on-a-basket.md): Prices the basket from ids alone (exactly as checkout will) and quotes the code against it. A rejected code is NOT an error: it comes back as 200 with `{ valid: false, reason }`. `planId` is a dedicated plan slug, a TenantOS server id for a one-off stock machine, a cloud plan slug or a hosting plan… - [Credit balance and recent transactions](https://docs.server.express/api-reference/credits/credit-balance-and-recent-transactions.md): The account credit balance and the 50 most recent ledger entries, newest first. Credit is always GBP minor units. - [Raise a credit top-up invoice](https://docs.server.express/api-reference/credits/raise-a-credit-top-up-invoice.md): Creates an UNPAID invoice (due in 7 days) for the requested amount plus tax at the customer's billing-entity rate. The balance only grows once that invoice is paid. Writes a CREDIT_TOPUP_INVOICE audit log entry. Bounds are checked on the raw number regardless of currency (500–1,000,000 minor units). - [Coins the active crypto gateway accepts](https://docs.server.express/api-reference/payments/coins-the-active-crypto-gateway-accepts.md): Tickers the live gateway will take, for the pay dialog. Cached in memory for an hour. - [Dashboard summary](https://docs.server.express/api-reference/dashboard/dashboard-summary.md): Counts, the outstanding balance and the five most recent services, invoices and tickets. `outstandingBalance` sums every UNPAID/OVERDUE invoice converted to GBP; `outstandingBreakdown` gives the unconverted per-currency totals. Open abuse reports are counted across every service the caller can see,… - [Buy a specific in-stock dedicated server](https://docs.server.express/api-reference/dedicated/buy-a-specific-in-stock-dedicated-server.md): The one-off path: a TenantOS machine sitting in stock rather than a plan. Re-reads the machine from TenantOS to confirm it's still for sale and to take its price, applies any reseller discount and coupon, then creates a PENDING monthly service and an UNPAID invoice due in 7 days. The root password i… - [Order a dedicated server from a catalogue product](https://docs.server.express/api-reference/dedicated/order-a-dedicated-server-from-a-catalogue-product.md): Legacy product-based ordering. Creates a PENDING DEDICATED service and an UNPAID invoice (due in 7 days) for one billing cycle of the Product's price, taxed only when the product is taxable. Writes a DEPLOY_DEDICATED audit log entry. Unexpected failures return 500 with the underlying error message.… - [List in-stock dedicated servers](https://docs.server.express/api-reference/dedicated/list-in-stock-dedicated-servers.md): TenantOS machines currently assigned to the stock user with a parseable, non-zero price in their description. - [Order a dedicated server plan](https://docs.server.express/api-reference/dedicated/order-a-dedicated-server-plan.md): Orders a plan rather than a specific machine. A unit is picked from the plan's pool and held; the invoice is due when the hold ends, after which the unpaid order is cancelled. If nothing is racked, a build-to-order slot is reserved instead (`provisional: true`, with the plan's lead time). Pasted `ss… - [List OS install profiles for a machine or plan](https://docs.server.express/api-reference/dedicated/list-os-install-profiles-for-a-machine-or-plan.md): Installable TenantOS profiles (rescue, password-reset and disk-wipe profiles removed). Ask by `serverId` for a stock machine, or by `planSlug` for a plan, which answers from the next available unit. A plan with no TenantOS-backed unit free is built to order and returns an empty list. - [List your dedicated servers](https://docs.server.express/api-reference/dedicated/list-your-dedicated-servers.md): Dedicated servers you own plus any shared with you through a team, newest first. Database only — hardware comes from the cached TenantOS answer (or the inventory row before there is one) and power from the poller's columns, so this never waits on TenantOS. Without `limit` every server is returned an… - [Redeem a console ticket and redirect to the KVM](https://docs.server.express/api-reference/dedicated/redeem-a-console-ticket-and-redirect-to-the-kvm.md): Opened in a new browser tab, so it takes no Authorization header — the ticket is the credential. Tickets are single use, valid for 60 seconds, and minted by POST /v1/dedicated/{id}/console for one person and one server. Access (operate role, manageable billing status) is checked again on redemption.… - [List dedicated plans with live stock](https://docs.server.express/api-reference/dedicated/list-dedicated-plans-with-live-stock.md): The public dedicated catalogue: every active, listed plan ordered by sortOrder then price, with a live count of the machines behind it. No hostnames, TenantOS ids or unit-level secrets are returned. Cached in memory for 30 seconds and sent with `Cache-Control: public, max-age=30`. If the database re… - [Live stock counts by model and location](https://docs.server.express/api-reference/dedicated/live-stock-counts-by-model-and-location.md): Legacy stock counts for the marketing site's static catalogue fallback, aggregated from the TenantOS marketplace. Units are grouped by (model, location) parsed from the stock hostname convention `--` (e.g. `arn1-xeon2-64-03` → model `XEON2-64`, location `arn`); hostnames that don… - [Get a dedicated server's header data](https://docs.server.express/api-reference/dedicated/get-a-dedicated-servers-header-data.md): Header data for the server page, plus the shared `machine` shape and your `role` on it. Built from one cached TenantOS answer at most 30 seconds old. Readable by the owner and any team member. - [List abuse reports filed against a server](https://docs.server.express/api-reference/dedicated/list-abuse-reports-filed-against-a-server.md): Abuse reports on this service, newest first, each with its message thread oldest first. The reporter's email and source are deliberately withheld. Staff messages are attributed to "ServerExpress Abuse Team". Readable by the owner and any team member. Uncertain: the route doesn't restrict the service… - [Reply to an abuse report](https://docs.server.express/api-reference/dedicated/reply-to-an-abuse-report.md): Adds your reply to the report's thread. Needs operate access (owner, team ADMIN or OPERATOR). Unless the report is RESOLVED or CLOSED its status moves to CUSTOMER_REPLIED. Writes a REPLY_ABUSE_REPORT audit entry and notifies staff. - [List a server's activity log](https://docs.server.express/api-reference/dedicated/list-a-servers-activity-log.md): The 100 most recent customer-visible audit entries for this server, newest first. Staff-only actions (`ADMIN_*`) are excluded, IPs are dropped, and metadata is filtered to a short allow-list of scalar keys. Readable by the owner and any team member. - [List add-ons available and owned](https://docs.server.express/api-reference/dedicated/list-add-ons-available-and-owned.md): The active add-on catalogue for dedicated servers (by name) and the add-ons already on this server (newest first). Needs billing access (owner or team ADMIN). - [Order an add-on](https://docs.server.express/api-reference/dedicated/order-an-add-on.md): Creates a PENDING add-on on the server and an UNPAID invoice for it, due in 7 days, billed to the service owner (not the caller). Tax follows the owner's billing company when the add-on is taxable. Needs billing access (owner or team ADMIN). Writes an ORDER_ADDON audit entry. A 500 can carry the und… - [Cancel a dedicated server](https://docs.server.express/api-reference/dedicated/cancel-a-dedicated-server.md): Owner only — team members get 404. Without `immediate` the service goes CANCELLED and runs to the end of the paid period. With `immediate: true` the hardware is released back to stock right away and the service goes TERMINATED. Either way active add-ons are cancelled, the reason is stored on the ser… - [Mint a KVM console link](https://docs.server.express/api-reference/dedicated/mint-a-kvm-console-link.md): Returns a relative URL (`/v1/dedicated/console/go/`) that's good once, for 60 seconds. Open it against the API base URL in a new tab; that GET starts the TenantOS session and redirects to it, so the session URL never appears in JSON. Needs operate access and a manageable billing status (not… - [Reveal the server's root password](https://docs.server.express/api-reference/dedicated/reveal-the-servers-root-password.md): The root (or Administrator, on Windows) password we set at order time or on the last reinstall. `password` is null when we never set one. Needs operate access and a manageable billing status. Refused with 409 while a reinstall is running, since the stored password belongs to the OS being wiped. Ever… - [Get IPMI sensor graphs](https://docs.server.express/api-reference/dedicated/get-ipmi-sensor-graphs.md): The box's IPMI sensor readings for the range, thinned to at most 300 points per sensor and cached for a minute. `traffic` is always null — there's no switch monitoring behind our metal. Readable by the owner, any team member and staff. - [List the BMC's IPMI accounts](https://docs.server.express/api-reference/dedicated/list-the-bmcs-ipmi-accounts.md): Owner only — team members get 404, the same as a stranger. Lists the BMC's accounts by name and privilege; TenantOS never returns BMC passwords. `host` is always null because TenantOS doesn't expose the BMC address. Needs a manageable billing status. Any failure after the access checks (TenantOS unr… - [Rotate and reveal your IPMI password](https://docs.server.express/api-reference/dedicated/rotate-and-reveal-your-ipmi-password.md): Owner only. Needs two-factor authentication turned on and a valid second-factor code every time. Creates or rotates the `customer` BMC account with OPERATOR privilege (power and KVM, no account management) and a fresh 16-character password, shown once — it's never stored, so asking again rotates it… - [Get a server's billing summary](https://docs.server.express/api-reference/dedicated/get-a-servers-billing-summary.md): Order and deployment dates, recurring price, active add-ons and the 10 most recent invoices touching this server. All amounts are minor units. Needs billing access (owner or team ADMIN). - [Get a server's IP assignments](https://docs.server.express/api-reference/dedicated/get-a-servers-ip-assignments.md): The primary IP, port speed and every IP TenantOS has assigned to the box, from the cached TenantOS answer. Readable by the owner, any team member and staff. A server with no TenantOS id answers 404; if TenantOS has never answered for it the route answers 500. - [Set reverse DNS for an IP](https://docs.server.express/api-reference/dedicated/set-reverse-dns-for-an-ip.md): Sets the PTR record for one of this server's IPs. The IP must be assigned to this box in TenantOS (checked live), otherwise 403. A trailing dot on `ptr` is stripped. Needs operate access and a manageable billing status; staff may also call it and bypass the billing-status check. Writes an UPDATE_RDN… - [Get a server's notes](https://docs.server.express/api-reference/dedicated/get-a-servers-notes.md): Legacy endpoint kept for the old dedicated page; /v1/services/{id}/notes covers every service type and shares the same storage. Readable by the owner and any team member. Uncertain: the service type isn't restricted here. - [Save a server's notes](https://docs.server.express/api-reference/dedicated/save-a-servers-notes.md): Replaces the notes and stamps the time. At most 10 KB, measured in UTF-8 bytes. Null or a missing `notes` clears them. Needs operate access. - [Get a server's overview tab](https://docs.server.express/api-reference/dedicated/get-a-servers-overview-tab.md): Hardware, disks, port speed and IPs from the cached TenantOS answer (refreshed if older than 30 seconds; the last known answer when TenantOS is down). `uptime`, `ram.used`, `network.inbound/outbound` and every `rdns` are always "—", and `recentEvents` is always empty. Readable by the owner and any t… - [Send a power action](https://docs.server.express/api-reference/dedicated/send-a-power-action.md): Starts a power task and answers 202 with its id; watch it via GET /v1/tasks/{id} or the task stream. Needs operate access and a manageable billing status. Refused with 409 while another job is running on the box, and 422 when the server has no TenantOS id or its power controller doesn't support the… - [List install or rescue images for a server](https://docs.server.express/api-reference/dedicated/list-install-or-rescue-images-for-a-server.md): The TenantOS provisioning profiles this box can take, filtered by the same rule the reinstall and rescue routes enforce. Readable by the owner, any team member and staff. A server with no TenantOS id answers 404. - [Reinstall the operating system](https://docs.server.express/api-reference/dedicated/reinstall-the-operating-system.md): Wipes the box and installs the chosen profile. Answers 202 with a task id; the install itself takes around twenty minutes. Every check (profile fits this box, disk layout offered, SSH keys yours or the owner's, profile accepts keys) runs before TenantOS is asked, so a bad request is a 400, never a w… - [Raise a renewal invoice](https://docs.server.express/api-reference/dedicated/raise-a-renewal-invoice.md): Creates an UNPAID invoice, due in 7 days and billed to the service owner, covering the server and its active add-ons for the chosen period starting at the current nextDueDate. Longer periods discount the server line (not add-ons): 3 months 2%, 6 months 4%, 12 months 8%. Doesn't move nextDueDate itse… - [Check whether the server is in rescue mode](https://docs.server.express/api-reference/dedicated/check-whether-the-server-is-in-rescue-mode.md): Whether the box is booted into a rescue system, and since when (the latest ENABLE_RESCUE request, if nothing has asked to leave since). Readable by the owner, any team member and staff. - [Boot into a rescue image](https://docs.server.express/api-reference/dedicated/boot-into-a-rescue-image.md): Network-boots the box into a rescue image; disks are left alone. Answers 202 with a task id and, when the image takes one, a freshly generated root password for the rescue system — returned here and nowhere else. Needs operate access and a manageable billing status. 409 while another job is running;… - [Leave rescue mode](https://docs.server.express/api-reference/dedicated/leave-rescue-mode.md): Hard-resets the box so it boots from its own disks, closing any rescue install TenantOS still has open. Answers 202 with a task id. Allowed through even while TenantOS reports the box busy in rescue. Needs operate access and a manageable billing status. 409 if some other job is running; 422 when the… - [List support departments](https://docs.server.express/api-reference/tickets/list-support-departments.md): Active departments, in their configured order, for the new-ticket form. - [Upload a file for a ticket message](https://docs.server.express/api-reference/tickets/upload-a-file-for-a-ticket-message.md): Send the file's raw bytes as the body and its name in `?name=`. The upload stays pending until a ticket or message names its id in `attachmentIds`; unsent uploads are swept after 24 hours. Up to 10 MB (413). Accepted extensions: png, jpg, jpeg, gif, webp, pdf, zip, gz, tgz, txt, log, csv, json, conf… - [Discard an unsent upload](https://docs.server.express/api-reference/tickets/discard-an-unsent-upload.md): Deletes one of your own uploads that no message has claimed yet, along with the stored file. - [List your tickets](https://docs.server.express/api-reference/tickets/list-your-tickets.md): Every ticket you opened, newest first. `updatedAt` is the time of the latest reply. - [Open a ticket](https://docs.server.express/api-reference/tickets/open-a-ticket.md): Creates the ticket with your message as its first reply and attaches up to 5 pending uploads. An unknown or inactive `department` falls back to `general`; an unknown `priority` falls back to `normal`. Emails you a confirmation and alerts staff by email and Telegram (failures there never fail the req… - [Get a ticket and its conversation](https://docs.server.express/api-reference/tickets/get-a-ticket-and-its-conversation.md): The ticket with every message, oldest first. Staff replies sent under a team or persona name show that name, never the person behind it. Opening a ticket in your own browser session marks staff replies as read; impersonation sessions and API tokens don't. - [Download a file on your ticket](https://docs.server.express/api-reference/tickets/download-a-file-on-your-ticket.md): Streams the file. Images and PDFs are served inline with their real content type; everything else as `application/octet-stream` with an attachment disposition. Always sent with `X-Content-Type-Options: nosniff`. 410 when the record exists but the stored file is gone. - [Reply to a ticket](https://docs.server.express/api-reference/tickets/reply-to-a-ticket.md): Adds your reply, attaches up to 5 pending uploads, and sets the ticket to CUSTOMER_REPLY. A message may be empty only when it carries files. Closed tickets refuse replies (400). Staff are alerted by email and Telegram. 409 if an attachment is no longer pending. - [Order a web hosting plan](https://docs.server.express/api-reference/web-hosting/order-a-web-hosting-plan.md): Reserves a hosting plan: a PENDING service and an UNPAID invoice. The Plesk subscription is created once the invoice settles. The domain is lowercased and a leading `www.` stripped; a domain already hosted with us (not terminated) is rejected with 409, as is a full location. Unexpected failures retu… - [List your invoices](https://docs.server.express/api-reference/invoices/list-your-invoices.md): Newest first, paginated. Drafts are never shown. - [Combine open invoices into one](https://docs.server.express/api-reference/invoices/combine-open-invoices-into-one.md): Mints a new invoice that collects 2–50 of your open (UNPAID/OVERDUE) invoices so they can be paid in one go. They must share a currency and billing entity, none may already combine others, and none may already be covered by another open combined invoice (409). Requires a complete billing address (42… - [Get one invoice](https://docs.server.express/api-reference/invoices/get-one-invoice.md): Full invoice with line items, bill-from/bill-to blocks (addresses formatted for the country, newline-separated), what a combined invoice covers and which combined invoice covers this one. `heldUntil` is set for an unpaid dedicated order whose machine is on hold. Drafts return 404. - [Bank details for paying an invoice by transfer](https://docs.server.express/api-reference/invoices/bank-details-for-paying-an-invoice-by-transfer.md): Where to send the money, how much, and the reference (the invoice number). Only for invoices genuinely owed: paid → 400; cancelled/refunded, inside an open combined invoice, or in a currency we hold no bank account for → 409. - [Tell staff a bank transfer is on its way](https://docs.server.express/api-reference/invoices/tell-staff-a-bank-transfer-is-on-its-way.md): A heads-up, not a payment: nothing is marked paid. Writes a BANK_TRANSFER_SENT audit log entry and pings staff on Telegram and Discord — at most once per invoice per 24 hours; repeat calls still return `noted: true`. Same payability checks as GET. Rate limited to 6 requests per minute per IP. Requir… - [Download an invoice as PDF](https://docs.server.express/api-reference/invoices/download-an-invoice-as-pdf.md): Same PDF as /pdf but sent as an attachment (`Content-Disposition` attachment; filename="invoice-.pdf"). Session only — API tokens are refused. Drafts return 404. - [Poll a crypto payment's status](https://docs.server.express/api-reference/invoices/poll-a-crypto-payments-status.md): Asks the gateway that minted the payment for its status, to drive the pay dialog's spinner. The webhook is what actually settles the invoice. The payment must belong to this invoice. Unexpected failures return 500 with the underlying error message. Uncertain — unlike the other invoice routes, this l… - [Pay an invoice](https://docs.server.express/api-reference/invoices/pay-an-invoice.md): Starts or completes payment, depending on `method`: - [View an invoice as PDF](https://docs.server.express/api-reference/invoices/view-an-invoice-as-pdf.md): The invoice PDF, served inline (`Content-Disposition` inline; filename="invoice-.pdf"). Accepts API tokens. Uncertain — unlike /download, this lookup doesn't exclude drafts. - [List catalogue products](https://docs.server.express/api-reference/products/list-catalogue-products.md): Active Product rows, cheapest first, optionally filtered by type. - [Send a contact-form message](https://docs.server.express/api-reference/public/send-a-contact-form-message.md): Relays a marketing-site contact form to the chosen department's mailbox, with the sender as Reply-To. Fields are trimmed and silently cut to their maximum length. A filled-in `website` honeypot gets a fake 200 and the message is dropped. Limited to 5 messages per IP per hour (in memory). 502 if the… - [Get currency conversion rates](https://docs.server.express/api-reference/public/get-currency-conversion-rates.md): Foreign units per £1, for quoting GBP catalogue prices in EUR and USD. Rates come from XE or the ECB (cached 24 hours upstream) and this response is cached for 60 seconds (`Cache-Control: public, max-age=60`). If a source fails, the missing legs fall back to a fixed table and `stale` is true. Never… - [Unsubscribe from marketing email](https://docs.server.express/api-reference/public/unsubscribe-from-marketing-email.md): One-click unsubscribe from the link in a marketing email. No session needed — the token is an HMAC of the user id, so the link works forever and can't be pointed at anyone else. Turns off the `marketing` notification preference (the same toggle Settings uses) and stamps `marketingUnsubscribedAt`. Bi… - [Health check](https://docs.server.express/api-reference/health/health-check.md): Is the HTTP server up with its routes registered? Deliberately doesn't touch the database, so a database blip doesn't get every container killed by the orchestrator. - [List your hosting subscriptions](https://docs.server.express/api-reference/hosting/list-your-hosting-subscriptions.md): Web hosting subscriptions you own plus any shared with you through a team, newest first. - [List hosting locations](https://docs.server.express/api-reference/hosting/list-hosting-locations.md): Locations that are switched on and have a live Plesk node — nowhere an order would fail. - [List hosting plans](https://docs.server.express/api-reference/hosting/list-hosting-plans.md): The shared-hosting catalogue priced in the requested currency: a hand-set price for that currency when there is one, otherwise converted from the plan's base price (`priceEstimated: true`). - [Get a hosting subscription](https://docs.server.express/api-reference/hosting/get-a-hosting-subscription.md): One subscription with its plan limits and, when the account is ACTIVE and Plesk answers, live disk and traffic usage. Usage is best-effort: if Plesk is slow or down `usage` is null and the rest still loads. `provisionError` explains a stuck order. Readable by the owner and any team member. - [Cancel a hosting subscription](https://docs.server.express/api-reference/hosting/cancel-a-hosting-subscription.md): Owner only — team members get 404. Without `immediate` the service goes CANCELLED and keeps running until nextDueDate. With `immediate: true` the Plesk subscription is deleted now — site, mail and databases with it — and the service goes TERMINATED; if Plesk refuses, nothing is cancelled and the rou… - [Reveal the FTP and panel login](https://docs.server.express/api-reference/hosting/reveal-the-ftp-and-panel-login.md): Owner only. Returns the plaintext FTP/panel password (null if none is stored or encryption isn't configured), the server hostname and the domain. Every call writes a REVEAL_HOSTING_CREDENTIALS audit entry. 404 also covers a subscription whose hosting account isn't set up yet. - [Get a one-time Plesk login link](https://docs.server.express/api-reference/hosting/get-a-one-time-plesk-login-link.md): Owner only — the link signs into the customer's whole Plesk login, not just this subscription. Short-lived and single use on Plesk's side, never stored; each call mints a fresh one. 409 when the subscription is suspended or hosting isn't set up yet. Writes a PANEL_SSO audit entry. - [Start a live chat session](https://docs.server.express/api-reference/livechat/start-a-live-chat-session.md): Opens a live chat bridged to a Discord thread and returns a WebSocket URL to connect to. Works signed in or anonymous. If an Authorization header is sent it must be a valid session (otherwise 401), and the account's name and email override whatever the body says. Anonymous visitors must send a `name… - [Look up DNS records](https://docs.server.express/api-reference/public-tools/look-up-dns-records.md): Resolves one record type, or with no `type` the everyday set (A, AAAA, CNAME, MX, NS, TXT, SOA, CAA). A type with no records comes back empty rather than as an error; 404 only when every type is empty. IP addresses are refused — pass a domain. Limited to 30 requests per minute per IP. - [Check a domain's email DNS (MX, SPF, DKIM, DMARC)](https://docs.server.express/api-reference/public-tools/check-a-domains-email-dns-mx-spf-dkim-dmarc.md): One DNS-only report on whether a domain is set up to send mail convincingly, with plain-English findings worst first. DKIM is probed on a fixed list of common selectors (default, google, selector1, selector2, k1, mail, s1, dkim), since DKIM has no way to list them. Nothing connects to a mail server.… - [Show the caller's IP address](https://docs.server.express/api-reference/public-tools/show-the-callers-ip-address.md): Your own address as the API sees it, its reverse DNS, and what the regional registry says about the network it sits in. Network details are cached per /24 (or /48 for IPv6), never per address, and nothing is stored. `network` is null if the registry lookup fails. Limited to 60 requests per minute pe… - [Inspect a host's TLS certificate](https://docs.server.express/api-reference/public-tools/inspect-a-hosts-tls-certificate.md): Does a TLS handshake and reports on the certificate: issuer, names covered, expiry, whether it matches the host, and the chain. Deliberately talks to hosts with broken certificates — that's when you need it. Names that resolve to private addresses are refused. On the Workers runtime the handshake go… - [Look up a WHOIS / RDAP record](https://docs.server.express/api-reference/public-tools/look-up-a-whois-rdap-record.md): Registry record for a domain, an IP address or an AS number. Tries RDAP first and falls back to port-43 WHOIS, following referrals. Answers are cached in memory for an hour; `cached` says whether this one was. 404 means the domain isn't registered. Limited to 20 requests per minute per IP. - [View an invoice from a public link](https://docs.server.express/api-reference/public-invoices/view-an-invoice-from-a-public-link.md): The login-free invoice view. Holding the token is the authorisation; staff mint and revoke it. Shows only what a paper invoice would. Money is in integer minor units of `currency`. A token shorter than 16 characters, an unknown token and a DRAFT invoice are all 404. - [Start paying an invoice from a public link](https://docs.server.express/api-reference/public-invoices/start-paying-an-invoice-from-a-public-link.md): Creates a hosted checkout (Stripe or the active crypto gateway) for the invoice's full total, records a pending payment against the invoice owner, and returns the checkout URL. Success and cancel both land back on the public invoice page. One checkout per method per invoice per minute (429 otherwise… - [Download an invoice PDF from a public link](https://docs.server.express/api-reference/public-invoices/download-an-invoice-pdf-from-a-public-link.md): The invoice as a PDF, served inline as `invoice-.pdf`. Same trust model as the JSON view: the token is the authorisation, and unknown tokens or DRAFT invoices are 404. - [List available payment methods](https://docs.server.express/api-reference/public-invoices/list-available-payment-methods.md): Which ways of paying are open right now, so a payment page can hide the card button before anyone clicks it. Sent with `Cache-Control: no-store` — staff switch cards off expecting it to bite immediately. - [Get the reseller catalogue](https://docs.server.express/api-reference/reseller/get-the-reseller-catalogue.md): Everything orderable — dedicated, cloud and hosting — with both the storefront `list` price and the `net` price this account pays (after its reseller discount) on every row. All amounts are minor units. Dedicated rows split stock into racked machines (ship on payment when `instant`) and build slots… - [Order a cloud server](https://docs.server.express/api-reference/reseller/order-a-cloud-server.md): Places a real order: a PENDING service and an unpaid invoice at this account's reseller rate. The VM is cloned once the invoice settles. Same code path as the panel. 428 when the account's billing details are incomplete; 403 for a restricted billing country. - [Order a dedicated server](https://docs.server.express/api-reference/reseller/order-a-dedicated-server.md): Places a real order: a machine comes out of the pool (or a build slot is taken), a PENDING service is created and an invoice is raised at this account's reseller rate (price plus setup). Provisioning happens when the invoice settles; `fulfilment` says whether that's instant or built by hand to `lead… - [Order shared hosting](https://docs.server.express/api-reference/reseller/order-shared-hosting.md): Places a real order for a hosting subscription at this account's reseller rate. A leading `www.` is stripped from the domain; a domain we already host is refused with 409 before any money moves, as is a full or unavailable location or plan. 428 when billing details are incomplete; 403 for a restrict… - [List your servers](https://docs.server.express/api-reference/services/list-your-servers.md): Every cloud and dedicated server the caller can see — their own and their teams' — in one cursor-paged list, newest first (createdAt then id, descending). Database only: `power` is the poller's last reading, never a live call. `q` matches the label, hostname, primary IPv4 (prefix), service id (prefi… - [Run a power action on many servers](https://docs.server.express/api-reference/services/run-a-power-action-on-many-servers.md): One power verb across up to 100 servers (cloud and dedicated mixed; duplicate ids are collapsed). Always 200 with one result per id in the order sent — a server that can't be powered (not yours, suspended, pending, terminated, no graceful shutdown on metal, unsupported by its BMC, already busy) is i… - [Add a tag to many servers](https://docs.server.express/api-reference/services/add-a-tag-to-many-servers.md): Adds one tag to each listed server the caller can operate. Per-server results: a server you can't change, or one already carrying 20 tags, fails on its own row. Adding a tag a server already has is a success. Tagging rides on the `services:power` scope. - [Remove a tag from many servers](https://docs.server.express/api-reference/services/remove-a-tag-from-many-servers.md): Takes one tag off each listed server the caller can operate. Removing a tag a server doesn't have is a success. The request carries a JSON body. - [Rename a server](https://docs.server.express/api-reference/services/rename-a-server.md): Changes the server's label only — never the hostname, Proxmox VM name or TenantOS record. CLOUD, VPS and DEDICATED services only; requires operate access. Sending the current label is a no-op success. Writes a RENAME_SERVICE audit entry (shown on the activity tab). Browser sessions only — API tokens… - [List abuse reports against a server](https://docs.server.express/api-reference/services/list-abuse-reports-against-a-server.md): Abuse reports filed against this service, newest first, each with its message thread (oldest first). Works for any service type; read access (owner or any team role) is enough. Reporter email and source are deliberately omitted. Staff messages are authored as "ServerExpress Abuse Team". Same handler… - [Reply to an abuse report](https://docs.server.express/api-reference/services/reply-to-an-abuse-report.md): Adds a customer reply to a report on this service. Requires operate access. Unless the report is RESOLVED or CLOSED its status moves to CUSTOMER_REPLIED. Writes a REPLY_ABUSE_REPORT audit entry and notifies staff on Discord. Same handler as POST /v1/dedicated/{id}/abuse/{reportId}/reply. - [Server activity feed](https://docs.server.express/api-reference/services/server-activity-feed.md): What was done to this server, by whom, and how it went — audit rows and task rows merged into one event each, newest first. Customer-safe copy only. Read access is enough; staff may read any server and see real names, while customers see staff as "ServerExpress". - [Read a server's notes](https://docs.server.express/api-reference/services/read-a-servers-notes.md): Free-text notes kept on the server (stored in Service.metadata). Any service type; read access or staff. - [Save a server's notes](https://docs.server.express/api-reference/services/save-a-servers-notes.md): Replaces the notes and stamps `updatedAt`. Requires operate access (staff allowed). Writes an UPDATE_NOTES audit entry that never records the content. Browser sessions only — API tokens are rejected. - [List your running and recent tasks](https://docs.server.express/api-reference/tasks/list-your-running-and-recent-tasks.md): Up to 20 tasks you started that are pending or running, or finished in the last five minutes, newest first. Tasks that have gone silent for over 30 minutes are marked failed and left out. Customers get a redacted view (`log` empty, `result` null, host- and address-like text in `step` replaced); admi… - [Get a task](https://docs.server.express/api-reference/tasks/get-a-task.md): A snapshot of one task. Visible to whoever started it and to admins; anyone else gets 404. Customers get the redacted view described on GET /v1/tasks. - [Link a Discord account](https://docs.server.express/api-reference/integrations/link-a-discord-account.md): Exchanges a Discord OAuth authorization code for a token, reads the Discord user and stores its id and display name on the profile. A Discord account can be linked to only one user (409 otherwise). Writes a LINK_DISCORD audit entry. A failed code exchange surfaces as 500. - [Unlink Discord](https://docs.server.express/api-reference/integrations/unlink-discord.md): Clears the Discord id and username from the profile. Idempotent. Writes an UNLINK_DISCORD audit entry. - [Link a Telegram account](https://docs.server.express/api-reference/integrations/link-a-telegram-account.md): Takes the payload from the Telegram Login Widget, verifies its HMAC `hash`, and stores the Telegram id and username on the profile. Bad widget data returns 401. A Telegram account can be linked to only one user (409 otherwise). Writes a LINK_TELEGRAM audit entry. - [Unlink Telegram](https://docs.server.express/api-reference/integrations/unlink-telegram.md): Clears the Telegram id and username from the profile. Idempotent. Writes an UNLINK_TELEGRAM audit entry. - [Get notification preferences](https://docs.server.express/api-reference/notifications/get-notification-preferences.md): Stored preferences merged over the defaults (email, billing, tickets on; marketing off). - [Update notification preferences](https://docs.server.express/api-reference/notifications/update-notification-preferences.md): Partial update — only the keys sent change. Writes an UPDATE_NOTIFICATION_PREFS audit entry. - [Notification feed](https://docs.server.express/api-reference/notifications/notification-feed.md): The bell's list, newest first, with the unread count so the badge and list come from one request. New notices also arrive live as `notice` frames on the task websocket; this is how a freshly opened page catches up. - [Mark every notice read](https://docs.server.express/api-reference/notifications/mark-every-notice-read.md): Marks all of the caller's unread notices read and returns a freshly counted unread total. Staff impersonating the customer change nothing. - [Mark one notice read](https://docs.server.express/api-reference/notifications/mark-one-notice-read.md): Marks the notice read. Scoped by owner in the write, so another user's id (or an already-read one) is a silent no-op rather than a 404. Staff impersonating the customer leave it unread. - [List passkeys](https://docs.server.express/api-reference/passkeys/list-passkeys.md): The caller's enrolled passkeys, newest first. - [Finish passkey enrollment](https://docs.server.express/api-reference/passkeys/finish-passkey-enrollment.md): Verifies the browser's `startRegistration()` result against the challenge minted by POST /v1/user/passkeys/options (single use, valid 5 minutes) and stores the credential. An expired/missing challenge or a failed verification is 400. Writes a PASSKEY_ENROLLED audit entry. - [Start passkey enrollment](https://docs.server.express/api-reference/passkeys/start-passkey-enrollment.md): Mints WebAuthn registration options for `startRegistration()` (attestation none, resident key and user verification preferred). Already-enrolled credentials are excluded. Stores the challenge for 5 minutes; starting again replaces it. No request body. - [Remove a passkey](https://docs.server.express/api-reference/passkeys/remove-a-passkey.md): Removes one of the caller's passkeys. Removing the last one turns two-factor sign-in off. Writes a PASSKEY_REMOVED audit entry. - [List SSH keys](https://docs.server.express/api-reference/ssh-keys/list-ssh-keys.md): The account's stored SSH public keys, newest first. Session only — an API token could otherwise grant shell on the next machine built. - [Add an SSH key](https://docs.server.express/api-reference/ssh-keys/add-an-ssh-key.md): Parses and validates an OpenSSH public key (ssh-ed25519, sk-ssh-ed25519@openssh.com, ssh-rsa, ecdsa-sha2-nistp256/384/521, sk-ecdsa-sha2-nistp256@openssh.com; DSA refused). Parse errors come back verbatim as 400. Max 50 keys per account and no duplicate fingerprints (409). Name defaults to the key c… - [Remove an SSH key](https://docs.server.express/api-reference/ssh-keys/remove-an-ssh-key.md): Removes the key from the account. Machines already built with it keep it until rebuilt or authorized_keys is edited. Writes a REMOVE_SSH_KEY audit entry. - [Rename an SSH key](https://docs.server.express/api-reference/ssh-keys/rename-an-ssh-key.md): Another user's key id reports 404, never 403. - [List your teams](https://docs.server.express/api-reference/teams/list-your-teams.md): Every team the caller owns or belongs to, oldest first. Teams never own servers — sharing only widens who may touch them. Session only. - [Create a team](https://docs.server.express/api-reference/teams/create-a-team.md): Creates a team with the caller as OWNER (and first member). Max 20 owned teams (409). Writes a TEAM_CREATED audit entry. - [Accept a team invite](https://docs.server.express/api-reference/teams/accept-a-team-invite.md): Joins the team with the invite's role. The signed-in account's email must match the invited address (403 otherwise). Unknown or revoked token → 404; already used → 409; expired → 410. If the caller is already a member the invite is stamped used and 200 is returned with `alreadyMember: true`. Writes… - [Decline a team invite](https://docs.server.express/api-reference/teams/decline-a-team-invite.md): Deletes the invite so the emailed link stops working. No sign-in needed — holding the token is enough, since the only outcome is deletion. Already accepted → 409. Writes a TEAM_INVITE_DECLINED audit entry. - [Get a team](https://docs.server.express/api-reference/teams/get-a-team.md): Members, pending invites and shared services. Any member may read it; `invites` is empty unless the caller can manage (OWNER or ADMIN). Expired invites stay listed with `expired: true`. Unpaid dedicated orders are left out of `services`. A team you're not in is 404. - [Delete a team](https://docs.server.express/api-reference/teams/delete-a-team.md): Owner only. Members and invites are deleted; shared services are simply unshared — nothing is cancelled, and they stay with the account that bought them. Writes a TEAM_DELETED audit entry. - [Rename a team](https://docs.server.express/api-reference/teams/rename-a-team.md): OWNER or ADMIN only (403 for other members). The same name again is a no-op success. Writes a TEAM_RENAMED audit entry. - [Invite someone to a team](https://docs.server.express/api-reference/teams/invite-someone-to-a-team.md): OWNER or ADMIN only. Emails a single-use link (32 random bytes, stored only as SHA-256) valid for 7 days. Re-inviting the same address replaces the old invite and token. 409 when inviting yourself, someone already in the team, past 50 pending invites, or racing another invite for the same address. W… - [Revoke a pending invite](https://docs.server.express/api-reference/teams/revoke-a-pending-invite.md): OWNER or ADMIN only. Hard-deletes the invite so the emailed link dies. An already-accepted invite is 409. Writes a TEAM_INVITE_REVOKED audit entry. - [List team members](https://docs.server.express/api-reference/teams/list-team-members.md): Everyone in the team, by join date. Any member may read it. - [Add a team member (sends an invite)](https://docs.server.express/api-reference/teams/add-a-team-member-sends-an-invite.md): Same action as POST /v1/user/teams/{id}/invites — nobody joins a team without accepting, so this emails an invite and returns 202. Same rules, limits and audit entry. - [Remove a member, or leave](https://docs.server.express/api-reference/teams/remove-a-member-or-leave.md): Any member may remove themselves (leave); removing someone else needs OWNER or ADMIN. The owner can't be removed or leave — they delete the team instead (403). Writes TEAM_MEMBER_LEFT or TEAM_MEMBER_REMOVED and sends a `team.member_removed` webhook to the team owner. - [Change a member's role](https://docs.server.express/api-reference/teams/change-a-members-role.md): OWNER or ADMIN only. Roles ADMIN, OPERATOR or VIEWER; asking for OWNER, or changing the owner's own role, is 403. Setting the role a member already has returns only `userId`, `role` and `name`. Writes a TEAM_MEMBER_ROLE_CHANGED audit entry. - [Share a service with a team](https://docs.server.express/api-reference/teams/share-a-service-with-a-team.md): Any member of the team may call it, but only the account that owns the service can share it (403 otherwise). A service belongs to at most one team, so sharing it here moves it from any previous team (`movedFromAnotherTeam`). Already shared with this team → 409. Writes a TEAM_SERVICE_SHARED audit ent… - [Stop sharing a service](https://docs.server.express/api-reference/teams/stop-sharing-a-service.md): The service owner or a team OWNER/ADMIN may unshare. Nothing is cancelled; the service goes back to being visible only to the account that bought it. Writes a TEAM_SERVICE_UNSHARED audit entry and sends a `team.service_shared` webhook (`shared: false`) to the team owner. - [List API tokens](https://docs.server.express/api-reference/api-tokens/list-api-tokens.md): The caller's live (unrevoked) tokens, newest first, plus the full scope catalogue so the UI needn't hardcode it. Session only — a token can never manage tokens. - [Create an API token](https://docs.server.express/api-reference/api-tokens/create-an-api-token.md): Mints a token and returns the plaintext once — it's never stored and can't be shown again. Max 20 live tokens (409). Duplicate scopes are collapsed. Writes an API_TOKEN_CREATED audit entry (scopes only, never the token). - [Revoke an API token](https://docs.server.express/api-reference/api-tokens/revoke-an-api-token.md): Soft revoke: the row stays, so a later call with the token is told it was revoked rather than invalid. Revoking an already-revoked token is a success with `alreadyRevoked: true`. Another user's token id is 404. Writes an API_TOKEN_REVOKED audit entry. - [List webhook endpoints](https://docs.server.express/api-reference/webhooks/list-webhook-endpoints.md): The caller's endpoints (newest first), the event catalogue, and how deliveries are signed. Secrets are never returned. Session only — a token must not be able to redirect the account's event stream. - [Create a webhook endpoint](https://docs.server.express/api-reference/webhooks/create-a-webhook-endpoint.md): Registers an endpoint and returns its signing secret once (stored encrypted; delete and recreate to rotate). The URL must be https on the default port, at most 2048 characters, with no embedded credentials, and resolve to a public host that isn't ours. Max 10 endpoints (409). 503 when server-side en… - [Delete a webhook endpoint](https://docs.server.express/api-reference/webhooks/delete-a-webhook-endpoint.md): Hard delete; the delivery log goes with it. Writes a WEBHOOK_ENDPOINT_DELETED audit entry. - [Update a webhook endpoint](https://docs.server.express/api-reference/webhooks/update-a-webhook-endpoint.md): Change the URL, description, events, or switch it on/off. At least one field is required. Re-enabling clears the failure counter and `disabledAt`; disabling stamps `disabledAt`. The secret can't be changed here. Another user's id is 404. Writes a WEBHOOK_ENDPOINT_UPDATED audit entry. - [Webhook delivery log](https://docs.server.express/api-reference/webhooks/webhook-delivery-log.md): Recent delivery attempts for one endpoint, newest first, including the exact payload so you can replay it. Out-of-range limits are clamped rather than rejected. - [Send a test ping](https://docs.server.express/api-reference/webhooks/send-a-test-ping.md): Sends a `ping` event to the endpoint synchronously and returns how it went (capped by the 10-second request timeout). A failed ping retries on the normal schedule. Switched-off endpoint → 409. Rate limited to 6 requests per minute. ## OpenAPI Specs - [openapi](/api-reference/openapi.yaml) This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.