# Authentication URL: https://wpocto.com/docs/api/authentication A workspace API key, sent as a bearer token. ## Create a key [#create-a-key] In the dashboard, a workspace **administrator** opens **Workspace settings → API keys** and creates one. The key is shown once; copy it into the integration's configuration. A key identifies the workspace, not a person, and keeps working when the person who made it leaves the workspace. Revoke a key from the same page. It stops working at once. ## Send it [#send-it] Every request carries the key as a bearer token: ```http GET /api/v1/dashboard/websites HTTP/1.1 Host: wpocto.com Accept: application/json Authorization: Bearer ``` A request without a valid key is answered with `401`. ## Keep it where it belongs [#keep-it-where-it-belongs] The key opens this platform. It does not belong on a managed WordPress site, in a browser, or in a repository. A site holds a different credential — the workspace token — for a different purpose, and the two are not interchangeable; see [Secrets](/application/security/credentials). ## From the reference pages [#from-the-reference-pages] The [API reference](/api/reference) lets you try each operation from the page. Enter your key once in the authorization field; it is used for the requests you make from that browser and is not stored by the documentation site. --- # Authorization URL: https://wpocto.com/docs/api/authorization What a key can read, and the one rule that decides it. A key is scoped to the workspace that created it. Every list it reads and every record it can open belongs to that workspace; a record in another workspace does not exist as far as the key is concerned, whether it is asked for by list, by id or by search. That scoping is a property of every endpoint, not something an endpoint opts into. There are no per-key permissions in `v1`. A key reads what an administrator of the workspace can see in the dashboard, for the resources the API exposes. Requests are made in the context of the key's workspace, so nothing in the request names a workspace: there is no workspace id to pass and none is accepted. --- # Changes URL: https://wpocto.com/docs/api/changes What was added to or changed in the API, by application release. The API is versioned in the path. Within `v1`, fields are added and never removed or renamed; anything that would break an integration goes in a new version. ## v1 [#v1] * **Websites** — `GET /api/v1/dashboard/websites`, paginated and sortable, each website with its package and the result of its last update round. Nothing in `v1` has been removed. When an endpoint is added the [reference](/api/reference) is regenerated from the application and this page gains a line. --- # Errors URL: https://wpocto.com/docs/api/errors The status codes the API answers with, and what each means. | Status | Meaning | | ------ | ------------------------------------------------------------------------------ | | `200` | the request succeeded and the body is the result | | `401` | no key, or a key that is not valid — [Authentication](/api/authentication) | | `403` | the key is valid but may not do this | | `404` | no such record in this workspace, or no such route | | `422` | a parameter did not validate; the body names the field and the problem | | `429` | too many requests; wait for the time in `Retry-After` | | `500` | something went wrong on the platform; retry later and report it if it persists | Error bodies are JSON with a `message`. A `422` adds an `errors` object keyed by parameter name. --- # API overview URL: https://wpocto.com/docs/api A small, versioned HTTP API for reading a workspace's data from an integration. The WP Octo API lets an integration read what a workspace sees in its dashboard. It is deliberately small: today it exposes the workspace's websites, with their package and the outcome of their last update round. It grows as integrations need more, and each addition is recorded under [Changes](/api/changes). | | | | -------------- | ---------------------------------------------------------------------------------------- | | Base URL | `https://wpocto.com/api/v1` | | Format | JSON, UTF-8 | | Authentication | a workspace API key as a bearer token — [Authentication](/api/authentication) | | Scope | the workspace the key belongs to, and nothing else — [Authorization](/api/authorization) | | Versioning | in the path; `v1` is the current and only version | ## The reference [#the-reference] The [API reference](/api/reference) is generated from the application's own routes, controllers and response classes, so it describes what the code does rather than what someone remembered it doing. Every operation there can be tried from the page against `https://wpocto.com` with your own key. ## What the API is not [#what-the-api-is-not] * **It is not the way to talk to a site.** The platform talks to the worker on a managed site over a channel of its own, which is not a public interface and is not documented as one. * **It does not issue keys.** A key is created in the dashboard by a workspace administrator. There is no login endpoint that returns one. * **It does not act on sites.** Starting an update round, a backup or a restore is done in the dashboard. Write operations are not part of `v1` at this time. --- # Pagination and sorting URL: https://wpocto.com/docs/api/pagination How list endpoints page and sort. List endpoints return one page at a time: the page's contents under `data`, the paging state under `meta` (current page, per page, total) and the neighbouring pages under `links`. | Parameter | Meaning | | ---------- | ---------------------------------------------------- | | `page` | the page to return, starting at 1 | | `per_page` | how many records per page | | `sort_by` | the field to sort by, where the endpoint supports it | ```http GET /api/v1/dashboard/websites?page=2&per_page=25&sort_by=name ``` The reference page of each list endpoint states which parameters it accepts and which fields it can sort by. --- # Backups URL: https://wpocto.com/docs/application/backups How a site is backed up, where the copies go, what "completed" means, and how the records are kept honest. ## What a backup is [#what-a-backup-is] A full backup of the site — files and database — made by the worker in steps small enough for shared hosting, written as chunks with a manifest, and verified before it is called complete. A backup can be kept on the site, in the workspace's object storage, or both, and can be restored from either copy. ## Schedules [#schedules] The site's **package** sets a **backup interval**: none, hourly, every four, six or twelve hours, daily, weekly or monthly. A site can override it. Daily and slower schedules land in a night window (four hours from one in the morning, in the workspace's timezone) at a minute of the site's own; sub-daily ones are spread once and then run exactly one interval apart. A manual backup never moves the schedule. A change of policy reschedules from now. A slot the platform cannot honour — the worker is unreachable, or the policy needs external storage the workspace has not configured — produces a failed backup that says why, and one retry an hour later. A policy that needs external storage is never quietly downgraded to keeping the copy on the site. ## Storage policies [#storage-policies] | Policy | The site's copy | The external copy | | ---------------------- | ------------------------------------------- | --------------------- | | **Local only** | kept | none | | **Local and external** | kept | uploaded and verified | | **External** | released once the external copy is verified | uploaded and verified | External storage is an S3-compatible bucket that WP Octo configures for your workspace; ask support to set it up or change it. The site never holds its credential. The choice offered on a site or package is restricted to what the workspace has. ## What "completed" means [#what-completed-means] A backup reaches **completed** only after the platform has verified every chunk of every copy it promised: for the external copy, one read of each object's size and checksum against what the site computed, now, rather than trusting that an upload said it succeeded. A backup whose verification fails says which chunk. ## Progress and failure [#progress-and-failure] The platform drives the worker step by step and continues where the last step stopped. It decides that a backup has failed from the site's own reported progress: no change for a set time is a stall, and a backup older than its ceiling is a timeout. A slow backup is not a failed one. Nothing else ends a backup except the worker saying so. The **Backups** page of a site shows each backup with its state and both copies, and offers **Resume** for one that stopped, **Check copies** to reconcile now, and **Sync status** to ask the site. The fleet-wide **Backups** page lists every backup in the workspace, with **Restore** offered only where a restore point exists. ## The records are never the proof [#the-records-are-never-the-proof] Every hour, and after every backup, restore and delete, the platform reconciles its records against the site and the storage: the site says whether the local copy is there; the storage says whether every chunk of the external copy is; the platform's rows are corrected to match. A copy that cannot be asked is *unreachable*, not *missing*, and still counts until an answer says otherwise. Nothing is deleted on either side by reconciliation; a leftover is a finding. A completed backup the platform did not know about — on the site, or in storage — is registered and verified before it is offered. ## Deleting a backup [#deleting-a-backup] Deleting a backup removes both copies and the record. The site's copy is removed through the worker; the external copy from the storage. --- # Billing URL: https://wpocto.com/docs/application/billing Plans, subscriptions, orders and transactions. Where WP Octo is sold as a self-service plan, the subscription is paid through the payment provider the platform is set up with (Stripe, Paddle and Lemon Squeezy are supported). Under **Workspace settings → Billing** an administrator sees the plan, the subscription, the orders and the transactions, and can change plan or cancel. A subscription that is about to expire is announced by email. Where WP Octo is provided under an agreement rather than a self-service plan, this page is not used. --- # Changelog URL: https://wpocto.com/docs/application/changelog What changed in the WP Octo application, by date. Newest first. {/* Generated by scripts/generate-changelogs.ts. Do not edit by hand; edit the source named below and run `npm run changelog:generate`. */} {/* Source: changelogs/application.md. */} The application is updated for everyone at once, so what matters is the day a change reached you. Each entry names the part of the product it is in. ## 17-09-2026 [#17-09-2026] * **Improved** – plugins and themes: Each plugin or theme appears once in the lists, however many sites carry it; duplicate entries have been merged with their sites, versions and advisories kept * **Improved** – security: A vulnerability check that cannot judge one advisory continues with the rest, and the drawer says why a version is not checked instead of leaving it blank * **Improved** – plugins and themes: A website's own Plugins and Themes pages show the same risk, version and status columns as the workspace lists, with their actions kept * **Added** – plugins and themes: A plugin or theme whose author has not released anything in twelve months carries a label and a notice * **Improved** – plugins and themes: The Info tab shows a component's description in full, and the drawer's tabs no longer shift after the first click * **Added** – website overview: A website opens with its health score, the time of the last check, one row per aspect that is measured, and a list of what needs attention * **Improved** – dashboard: Fleet health on the workspace dashboard is shown as the average health score of the checked sites * **Fixed** – navigation: The active menu item has its marker and highlight back ## 16-09-2026 [#16-09-2026] * **Added** – plugins and themes: One row per plugin or theme, with a drawer holding its vulnerabilities, information, changelog, sites and versions, a risk badge per row, icons, and a Vulnerable only filter * **Added** – websites: A website's own Plugins and Themes pages open the same drawer, every website has an Activity page, and the Reports page carries the website header * **Added** – navigation: Control Center is a navigation tree under Websites, and a website's pages open with the main menu collapsed * **Fixed** – plugins and themes: Plugins are recognised by their folder, so information and vulnerability lookups resolve for components that were previously unmatched ## 15-09-2026 [#15-09-2026] * **Fixed** – updates: An update round in a state the dashboard does not recognise is shown as an unknown status in the activity feed and on the Update Rounds pages instead of an error ## 14-09-2026 [#14-09-2026] * **Fixed** – security: Vulnerability checks store their results again, and the plugin and theme lists show status, severity and the version that fixes an advisory * **Fixed** – websites: The websites list summary and the fleet summary labels no longer overflow their space ## 13-09-2026 [#13-09-2026] * **Added** – security: Plugins, themes and core versions across the fleet are checked against known vulnerabilities * **Security** – updates: The bulk Run update round action is hidden from members without the permission to run update rounds * **Security** – access: The Websites and Update Rounds lists are confined to the current workspace explicitly * **Fixed** – subscriptions: The subscription lists skip a plan they cannot render instead of failing * **Fixed** – websites: The website Settings header no longer overlaps its actions on desktop * **Fixed** – announcements: An announcement no longer appears before its place on the page exists, and one dismissed from its close button stays dismissed * **Fixed** – updates: The update-round chart draws in the panel's colours, and its link applies the completion filter it names * **Improved** – plugins and themes: Plugin and theme icons sit on a surface that follows light and dark mode ## 12-09-2026 [#12-09-2026] * **Fixed** – dashboard: On a phone the dashboard widgets no longer stay on loading or overlap the website header * **Added** – websites: A site's thumbnail condition is readable in the panel, as a list column, a badge in the site header and a fleet metric for thumbnail issues * **Improved** – updates: An update round that stalls is closed as abandoned and shown as such, instead of staying open indefinitely ## 08-09-2026 [#08-09-2026] * **Improved** – backups: A backup completes on a site whose host blocks WP Octo's calls, and is far lighter on the site while it runs * **Improved** – backups: A backup that is due starts promptly on a site WP Octo can reach, rather than waiting for the site's next scheduled task * **Improved** – health: A site that reports as expected is no longer shown as stale between two of its reports * **Improved** – worker updates: A site WP Octo could not reach during a worker update still receives the release through WordPress's own updates, and is recorded as updated once it has * **Fixed** – worker updates: A site WP Octo could not reach for a worker update is recorded as unreachable rather than as failed * **Fixed** – connection: A site whose host allows WP Octo, as its Health page instructs, is no longer reported as blocked by a firewall ## 07-09-2026 [#07-09-2026] * **Added** – backups: Scheduled backups from the package with a per-site override, storage policies for the site, object storage or both, and restore from the external copy * **Added** – backups: A central Backups page; Restore is offered only where a restore point exists, and the storage choice is limited to what the workspace has * **Improved** – backups: The backup list is checked against what is actually on the site and in storage, so a backup whose copies are gone is no longer offered for a restore * **Improved** – backups: A backup found on the site or in storage that WP Octo did not know about is verified in full before it is offered for a restore * **Added** – health: A site WP Octo cannot reach is shown with the cause — DNS, certificate, timeout, a firewall with the provider named, plugin inactive, authentication failed — is checked again on its own, and receives the worker release it missed once it is reachable again * **Improved** – health: A site blocked by its host's firewall shows on its Health page what to allow and where * **Added** – sync: A site keeps WP Octo up to date on its own, so a host firewall no longer leaves its plugins, themes, users, core, health and backups stale, and every site shows when its data was last received * **Added** – connection: A site running a JWT authentication plugin connects to WP Octo once its worker is current; that plugin used to stand in the way * **Improved** – updates: A plugin update the site refused for a permanent reason, such as a missing licence, is not retried, and the reason is recorded * **Improved** – roles: A member with the client role is read-only and can no longer log in to a site through the dashboard * **Security** – access: A client member is limited to the sites of the clients they are attached to everywhere, the API included * **Fixed** – sync: A site with many backups no longer fails its first report to WP Octo ## 06-09-2026 [#06-09-2026] * **Fixed** – sign in: The login page refused every password; signing in with a password works again * **Fixed** – updates: A plugin update the site refused is recorded as refused rather than as a success the site then disagreed with * **Improved** – regression: The regression results table loads in a fraction of the time and shows its screenshots in one view ## 03-09-2026 [#03-09-2026] * **Improved** – dashboard: Every screen follows the light or dark theme * **Improved** – updates: The outcome of a plugin update is verified against the site rather than taken from the site's own report * **Security** – access: The workspace API key is no longer visible to a read-only role --- # Clients URL: https://wpocto.com/docs/application/clients The customers the sites belong to. A **client** is a customer of your workspace: the company or person whose site it is. Every site is attached to one. A client has a name and a **notify** setting, which decides whether the daily update email about its sites is sent. It has **contacts** — the people at the customer — and can have **members** of the workspace attached to it with the *client* role, who then see the client's sites read-only in the dashboard. Members are invited from **Team**. Move a client's sites to another client before deleting it. --- # Dashboard URL: https://wpocto.com/docs/application/dashboard The fleet at a glance. The home screen of a workspace summarises its sites. ## Fleet overview [#fleet-overview] Four numbers across the top: **Websites** in the workspace, **Sites operational** — those whose worker is reachable and whose monitors are up — **Open issues**, and **Average health** across the fleet. ## Website health [#website-health] A chart of how the fleet's health is distributed, so a change across many sites is visible without opening them. ## Recent activity [#recent-activity] What happened lately across the fleet: update rounds finishing, backups completing, sites going down and coming back, workers updated. Each entry links to the site. ## Security status [#security-status] The one security signal the platform actually collects across the fleet: TLS certificates, from the uptime monitors — how many are valid, how many expire within thirty days, how many are invalid. Nothing here scans for threats or manages a firewall, and the card does not pretend to; see [what is not checked](/application/security#what-is-not-checked). ## Fleet alert [#fleet-alert] A banner across the top of the dashboard, shown only when a site is down or a certificate is invalid, with the sites named and a link to the list. It renders nothing when the fleet is healthy, on purpose: an always-present "everything is fine" banner trains people to stop reading it. It can be dismissed for the session. ## Update rounds [#update-rounds] The rounds in flight and the ones that finished recently, with their outcome. ## The websites table [#the-websites-table] The same list as the Websites page, in short: status, worker version, package, last update round, with the same row actions. --- # What WP Octo does URL: https://wpocto.com/docs/application A dashboard for a fleet of WordPress sites, and a plugin on every site that does the work. WP Octo manages many WordPress sites from one place. An agency or a hosting company connects each site it looks after, and WP Octo takes care of the routine: safe updates with a backup and a rollback, scheduled backups to object storage, uptime monitoring, and a record of what happened on every site. ## Two parts [#two-parts] * **The application**, at [wpocto.com](https://wpocto.com): the dashboard where sites are added, updates are run, backups are scheduled and restored, and monitoring is read. Every customer works in a **workspace** of their own; nothing in one workspace is visible from another. * **The worker plugin**, installed on every managed site. It performs updates, makes and restores backups, and reports the site's state. The application tells it what to do; the plugin does the work on the site itself, in steps small enough for shared hosting. It has a [section of its own](/worker). ## What it does for a site [#what-it-does-for-a-site] | | | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Updates** | Plugins, themes and WordPress core, in a scheduled round: a backup first, the updates, a check of the site's pages afterwards, and a rollback when the check fails. | | **Backups** | Made in steps, verified before they are called complete. Kept on the site, in object storage, or both, on the schedule the site's package sets. Restorable from either copy. | | **Monitoring** | Uptime and certificate checks on the site's pages, with a log per site and an email when a page goes down and when it comes back. | | **Inventory** | The site's plugins, themes, users and core version, kept current whether the platform can reach the site or only the site can reach the platform. | | **Recovery** | A plugin that keeps a rollback copy of itself and can be put back even when it cannot load, and a maintenance mode that lifts itself if a round never finishes. | ## How the dashboard is organised [#how-the-dashboard-is-organised] The dashboard is organised around the **website**: everything a site has — its plugins, its backups, its update rounds, its monitoring — is a page of that site, and the fleet-level pages summarise across sites. | Area | What is there | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Dashboard** | The fleet at a glance: how many sites, how many operational, open issues, average health, recent activity, security status, and the update rounds in flight. | | **Websites** | Every site in the workspace, with its status, worker version, package and last update round. Open one for its pages. | | **Update rounds** | Every update round across the fleet, with its outcome and the rollback actions. | | **Backups** | Every backup across the fleet, restorable or not, and where each copy is. | | **Clients** | The customers the sites belong to. | | **Packages** | The service levels sites are on. | | **Team** | The workspace's members and invitations. | | **Workspace settings** | Name and details, API keys, storage, billing where it applies. | A site's pages: Health · Plugins · Themes · Core · Users · Backups · Restores · Update rounds · Monitoring · Regression · Reports · Notes — and two placeholders, Security and Performance, which [say so on the page](/application/pages-not-yet-available). ## Who sees what [#who-sees-what] An **administrator** sees and does all of it. A **user** sees every site and its pages and can log in to a site, but changes nothing on the platform. A **client** sees only the sites of the client accounts they are attached to, read-only. [Roles and permissions](/application/roles-and-permissions) has the table. --- # Monitoring URL: https://wpocto.com/docs/application/monitoring Uptime and certificate checks on a site's pages, and the log of what they found. ## What is checked [#what-is-checked] When monitoring is on for a site, its home page and every page under [Regression](/application/regression) is checked for **uptime** — does it answer, with what status, how fast — on the site's **monitoring interval** (5, 15, 30, 45 or 60 minutes, from those the package allows), and its certificate is checked daily. ## When a page goes down [#when-a-page-goes-down] A failing page is checked again with a widening gap — one, two, four, eight, sixteen, thirty-two minutes, up to the site's own interval — so that a site that is down for an hour is asked about seven times rather than sixty, and a site that is down for a day no more often than a healthy one. That matters: a monitor that hammers a struggling site is what stops it recovering. Recovery is noticed within the interval. An email goes out when a page goes down and when it comes back — [Notifications](/application/notifications). ## The log [#the-log] The site's **Monitoring** page shows each monitored page with its current state and the log of the last ninety days. Every entry has a sentence a person can read — *The site did not answer within 15 seconds*, *The site answered 503 Service Unavailable* — and, folded underneath, the raw reason the check recorded, for whoever needs it. Machine output is never the entry's own line. ## Monitoring and the worker [#monitoring-and-the-worker] Monitoring reads the site's pages as a visitor would. It does not need the worker, and it says nothing about whether the platform can reach the worker; the site's Health page does that. A page behind a firewall that challenges non-browser clients can read as *up* to the monitor while the worker is unreachable. --- # Notes URL: https://wpocto.com/docs/application/notes Free-form notes on a site. The site's **Notes** page holds notes about the site — hosting details, who to call, what not to touch, why a plugin is deactivated. Administrators write and delete them. Every member who can see the site can read them, clients included, so a note is a good place for anything the customer should also know. Notes live on the platform, not on the site: they survive a restore of the site and are not part of a backup. --- # Notifications URL: https://wpocto.com/docs/application/notifications The emails the platform sends. | Email | To | When | | ---------------------------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------- | | **Updates performed** | the client's contacts, when the client's notify setting is on | daily, for the update rounds of the client's sites that completed | | **Updates not completed** | the same | daily, for rounds that did not complete, with the reason | | **A page is down** / **is back** | the workspace | when a monitored page fails and when it recovers | | **Certificate** | the workspace | when a site's certificate is about to expire or is invalid | | **Worker status changed** | shown in the dashboard's notification panel, not emailed | when a site's worker becomes unreachable and when it recovers | | **Invitation** | the invited person | on invitation | | **Verify email**, **reset password**, **two-factor** | the account | on those events | Update emails go to the client's contacts; monitoring emails go to the workspace's members. Mail is sent from `wpocto.com`. --- # Packages URL: https://wpocto.com/docs/application/packages The service level a site is on. A **package** bundles the settings that define a level of service. Define one per level you sell and assign one to every site. | Setting | Meaning | | ---------------------------- | ------------------------------------------------------------------------------------ | | **Name** | as shown on the site | | **Monthly and yearly price** | for your own records; the platform does not invoice your clients | | **Update frequency** | every so many days; with the site's update weekdays, when scheduled rounds run | | **Backup interval** | none, hourly, every four, six or twelve hours, daily, weekly, monthly | | **Backup storage policy** | local only, local and external, or external | | **Regression pages** | how many a site on this package may have | | **Monitoring** | on or off, and the longest interval a site may choose; a site may pick a shorter one | A site can override the backup interval and storage policy on its own record. Changing a package's backup settings reschedules every site on it from now. --- # Pages not yet available URL: https://wpocto.com/docs/application/pages-not-yet-available Two pages exist in the navigation and say so. Two pages of a site are present in the dashboard as placeholders: * **Security** — will hold the security findings about a site. Today the platform has no check for exposed log or debug files and does not scan plugin code; see [Boundaries](/application/security#what-is-not-checked). * **Performance** — will hold performance measurements. Today Lighthouse reports are under [Reports](/application/reports). Both show *Page not yet available*. They are listed here so that nobody looks for a feature that does not exist yet. --- # Plugins, themes and core URL: https://wpocto.com/docs/application/plugins-themes-and-core The site's inventory, and the one-at-a-time changes made from it. ## Plugins [#plugins] The **Plugins** page lists what the site reported: name, version, whether it is active, and whether an update is available. **Sync** asks the site again. From the list an administrator can **activate** or **deactivate** one plugin or several, and **update** a plugin that has an update on its own — outside an update round, without the round's backup and checks. Use an [update round](/application/updates) for anything you would want to be able to roll back. The worker refuses to delete itself through this page. ## Themes [#themes] The same for themes: what is installed, which is active, what has an update. Activate, deactivate, update. ## Core [#core] The site's WordPress version and the version available. Updating core from here updates it on its own; an update round does it with a backup first and the site's pages checked afterwards. ## How current the list is [#how-current-the-list-is] Each page shows when the platform last received that dataset from the site and over which channel — the platform's own read, or the site's report. A list that is older than a day is marked stale, and the age is shown rather than hidden; a site the platform cannot reach keeps reporting on its own schedule, so its list stays current anyway. [Connection problems](/application/troubleshooting/connection-problems) covers a list that stops updating. --- # Regression pages URL: https://wpocto.com/docs/application/regression The pages captured before and after an update round, and compared. A site's **Regression** page lists the pages the platform captures around an update round: each with its address, its comparison **threshold**, and its monitor status. The package sets how many a site may have. Before a round's updates the platform captures each page; after them it captures each again and compares. A difference above the page's threshold fails the round's verification, and the round rolls back. Choose pages that show the site's real templates — the home page, a post, a product, a form — rather than pages that change on every visit. The same pages are the ones [monitoring](/application/monitoring) checks. --- # Reports URL: https://wpocto.com/docs/application/reports Lighthouse reports and thumbnails. The site's **Reports** page holds Lighthouse reports of the site's home page. The platform generates one for every site weekly; **Generate** makes one now. A report is selected to view — performance, accessibility, best practices and SEO scores with Lighthouse's own findings — and can be deleted. A report's state is pending, processing, completed or failed; a failed one says why, usually that the page could not be reached. Thumbnails of the sites, shown in lists, are refreshed nightly. --- # Restores URL: https://wpocto.com/docs/application/restores Restoring a site from a backup, from either copy. ## Starting a restore [#starting-a-restore] From the site's **Backups** page or the fleet-wide list, a backup that is restorable offers an administrator **Restore database** and **Restore full**. A restore is confirmed before it starts; it changes the live site. ## What happens [#what-happens] * **From the site's copy**, the worker puts the database back and then the files, one piece at a time. A failure part-way rolls back rather than leaving half a database; the live site is unavailable only for the moment the new database is switched in. * **From the external copy**, the platform first brings the backup back onto the site: the worker downloads it from object storage piece by piece, through links the platform hands it that are valid for a limited time, and only a site holding a complete, verified copy is then asked to restore. A link that expires mid-download is renewed; the site keeps every piece it already has. The worker refuses a restore from a copy on the site whose files are not all there, rather than restoring whatever happens to be in the directory; the platform then restores from the external copy when there is a whole one, and says so if there is not. A restore is the only thing that runs on the site while it runs: no backup, update round or worker update starts on that site until it has finished. ## What a restore keeps [#what-a-restore-keeps] Since worker 2.3.0 a restore keeps the site's connection to the platform and the work in flight, rather than rolling them back to the backup's day. ## The Restores page [#the-restores-page] Each site's **Restores** page lists its restores with their phase — pending, fetching, preparing, processing, completed, failed, cancelled — the copy each read from, and the outcome. --- # Roles and permissions URL: https://wpocto.com/docs/application/roles-and-permissions What each role in a workspace may do. Every member has one role in the workspace. A role is a fixed set of permissions; there is no per-member customisation. | | Administrator | User | Client | | -------------------------------------------------------------------------------------------- | ----------------------- | ---- | -------------------------- | | See the workspace's sites | all | all | only the attached clients' | | Site pages: plugins, themes, core, health, security, performance, reports, notes, regression | yes | view | view | | Update rounds | run, roll back, delete | view | view | | Backups, restores, recoveries | create, restore, delete | view | view | | Log in to a site | yes | yes | no | | Add, edit, delete sites; sync; sitemap | yes | no | no | | Notes and regression pages | create, delete | view | view | | Clients and packages | manage | no | no | | Team, invitations | manage | no | no | | Workspace settings, API keys, billing | manage | no | no | Two of the three roles are read-only on the platform by construction: *user* and *client* hold view permissions and, for the user, the site login; every change — an update round, a backup, a restore, a site's settings — is an administrator's. Selecting many sites in a list gives nobody more than they have on one site. The difference between the two read-only roles is scope and the login: a user sees the whole fleet and may open a site's admin through the dashboard; a client sees the attached clients' sites and may not. The login was removed from the client role deliberately — it hands out an administrator session on the site itself, which is the opposite of read-only. --- # Site users and login URL: https://wpocto.com/docs/application/site-users-and-login The site's WordPress users, and logging in to a site without a password. ## Users [#users] The site's **Users** page lists its WordPress users as the site reported them, with their role. **Sync** asks again. An administrator can **edit** or **delete** a user on the site from here. ## Logging in [#logging-in] **Log in** on a site opens its WordPress admin as an administrator, without a password: the platform asks the worker for a ticket, valid once and for one minute, and the browser redeems it. It is available to administrators and users of the workspace, not to clients, and it is recorded in the site's activity log with the platform named as the actor. --- # Team URL: https://wpocto.com/docs/application/team Members and invitations. **Team** lists the workspace's members with their role, and the invitations that are open. An administrator invites a person by email with the role they should have — administrator, user or client; the invitation is accepted by signing in or registering with that address. A member's role can be changed and a member removed by an administrator. A member with the *client* role sees nothing until attached to a client — [Clients](/application/clients). What each role may do is in [Roles and permissions](/application/roles-and-permissions). --- # Updates URL: https://wpocto.com/docs/application/updates The update round — a backup, the updates, the checks, and the rollback when a check fails. An **update round** is how WP Octo updates a site. It is not a click on "update all": it is a sequence with a backup before it, checks after it, and a rollback when the checks fail, and every step of it is recorded. ## What a round does [#what-a-round-does] ### Prepare [#prepare] The platform checks that it can reach the site, that the site's worker is recent enough to bring the site back on its own if the platform disappears mid-round, and that the site's filesystem is writable where it needs to be. A site that fails any of these gets a round that ends with that reason and touches nothing. ### Back up [#back-up] The worker backs up the plugins that will be updated, the theme, and WordPress core, one component at a time, into the worker's backup directory. These are the rollback points for this round. ### Take a baseline [#take-a-baseline] Each of the site's regression pages is captured as it looks before the updates. ### Update [#update] The site goes into maintenance mode — a flag with a deadline, so that a round that never finishes cannot hold the site dark — and the worker updates plugins, then the theme, then core, one at a time. A plugin the worker cannot update says why: a premium plugin without a licence is not retried, a download that failed is. ### Verify [#verify] The site comes out of maintenance mode. The platform checks that the site's front page and its admin answer, then captures each regression page again and compares it with the baseline against the page's threshold. ### Roll back if needed [#roll-back-if-needed] When a check fails, the platform restores what the round changed from the backups it took — plugins, theme, core, or all of them — and records the round as rolled back with the reason. A round whose site the platform cannot bring back on its own is the case the worker's maintenance deadline exists for. ## Scheduled and manual rounds [#scheduled-and-manual-rounds] A round is started by the schedule or by a person: * **Scheduled.** The package's **update frequency** — every so many days — sets how often; the site's **update weekdays** set on which days. The platform checks every hour which sites are due and starts their rounds. * **Manual.** **Run update round** on a site, or on several from the list — an administrator's action. Both go through the same sequence and the same refusals. ## What a round records [#what-a-round-records] Every round has a status that says where it is or how it ended — preparing, backing up, updating plugins, verifying, completed, rolled back, ended unexpectedly, and the failed variants that name the step. Each plugin update in it records the attempt, the worker's answer, and whether the platform verified the new version on the site afterwards. A plugin the worker said it updated but the site does not show as updated is recorded as a verification failure, not as a success. ## Rollbacks by hand [#rollbacks-by-hand] From **Update rounds**, a finished round offers **rollback** actions — plugins, theme, core, or all — that restore the round's own backups. They are for a problem found after the round's checks passed. ## Update emails [#update-emails] Once a day the platform emails the client of each site whose rounds finished, with what was updated and what was not; a client can opt out on its record. [Notifications](/application/notifications) lists the emails. ## A round the platform refuses to start [#a-round-the-platform-refuses-to-start] A site whose worker is older than the version that brings a site back on its own is not given a round, by schedule or by hand, and the dashboard says so. The platform asks the site for its version at that moment rather than reading what it last reported, because a file restore can put an older worker back underneath a newer record. [Compatibility](/worker/versions) has the thresholds. --- # Websites URL: https://wpocto.com/docs/application/websites The list of sites, adding and editing one, connecting it, and the header every site page shares. ## The list [#the-list] Every site in the workspace, with its name and address, its client, its package, its worker status and version, its last update round, and its monitoring state. Star a site to keep it at the top. Search by name or address, and filter by worker status, health, package, client or starred. Row actions: **Edit**, open the **site** or its **admin** in a new tab, **log in** to the site's admin without a password (administrators and users; see [Site users and login](/application/site-users-and-login)), **run an update round** now, **run a health check**, and **delete**. Bulk actions run an update round, a health check or a connection refresh across the selected sites. What each role sees of these is in [Roles and permissions](/application/roles-and-permissions). ## Adding a site [#adding-a-site] **Websites → Create.** The fields: | | | | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Name** | as it appears in lists | | **URL** | the address the site answers on. It is checked for redirects before it is accepted; an address that redirects — `http` to `https`, without to with `www`, to another path — is refused, because a redirect would strip the credential from the platform's calls. Enter the address the site actually answers on, including the path when WordPress lives in a subdirectory. | | **Client** | the customer the site belongs to | | **Package** | the service level; it sets the update frequency, the backup interval and storage policy, the number of regression pages and the monitoring interval | | **Tags** | free-form, for filtering | | **Backup interval** and **storage policy** | inherited from the package unless overridden here | | **Monitoring** | on or off, and the interval, chosen from those the package allows | | **Update weekdays** | the days a scheduled update round may run on this site | | **Debug mode** | whether WordPress debug mode is on on the site | A new site is not connected until the worker is installed on it and paired — [Install the worker](/application/getting-started/install-the-worker). **Connect Website** on the edit page shows the steps and the download. ## The site header [#the-site-header] Every page of a site carries the same header: the site's name and address, its worker version and status, when it last reported, and the actions that apply everywhere — open the site, open its admin, log in, run an update round, run a health check. ## Health [#health] The site's **Health** page shows three separate facts: whether the platform can reach the site, when the site last called the platform, and the age and channel of each dataset the platform holds about it. Below them, the work the platform has handed the site that is not finished, and what needs attention, with an instruction where a person is needed. **Run health check** asks again now. [Connection problems](/application/troubleshooting/connection-problems) explains what each finding means. ## Deleting a site [#deleting-a-site] Deleting a site removes it from the workspace with its records. It does not touch the site itself: the worker stays installed and keeps the workspace token until it is deactivated or the token is removed. Remove the plugin from the site first if the site is leaving your care. --- # Workspace settings URL: https://wpocto.com/docs/application/workspace-settings Name and details, API keys, storage and billing. Available to administrators. ## General [#general] The workspace's name and details. ## API keys [#api-keys] Create and revoke the keys an integration uses to read the workspace through the [API](/api). A key is shown once. Keep it out of managed sites — [Secrets](/application/security/credentials). ## Storage [#storage] The object storage external backups go to is configured for the workspace by WP Octo, not from this page. A storage policy that needs external storage cannot be chosen until it is; ask support to set it up or change it. ## Billing [#billing] Where the workspace is on a paid plan: the plan, the subscription, orders and transactions — [Billing](/application/billing). ## Your own account [#your-own-account] Under your profile: name, email, password, two-factor authentication with recovery codes. --- # Changelog URL: https://wpocto.com/docs/worker/changelog What changed in the worker plugin, per stable version. Newest first. {/* Generated by scripts/generate-changelogs.ts. Do not edit by hand; edit the source named below and run `npm run changelog:generate`. */} {/* Source: changelogs/worker.json, exported from the worker plugin's own changelog by the application. */} Every version listed here was published as a stable release; a version appears once, on the day it was published, with each change as the plugin's own changelog states it. What you read on a site's **View details** screen for the plugin is the same list. ## 2.3.1 – 15-09-2026 [#231--15-09-2026] * **Fixed** – backups: A plugin table named like the WordPress options table is backed up and restored whole instead of failing every backup of the site * **Fixed** – commands: A task that ends in an error, or runs out of time or memory, is reported to WP Octo as failed instead of being lost, so WP Octo no longer waits on it for hours or starts it over * **Fixed** – credential: A credential WP Octo refuses once is offered again after a growing pause instead of being dropped for good, and the site reports the refusal so WP Octo can hand over a new one * **Fixed** – credential: When WP Octo hands over a credential, the site confirms what it actually stored and reports a store that did not persist instead of confirming a credential it does not hold ## 2.3.0 – 08-09-2026 [#230--08-09-2026] * **Added** – sync: The site reports its plugins, themes, users, core, health and backups to WP Octo on its own schedule, so a firewall that blocks WP Octo no longer leaves stale data * **Added** – commands: WP Octo hands the site signed, single-use instructions it carries out on its own clock, including a backup, an upload to storage, a release of its copy, a restore and its own update * **Added** – credential: Each site holds a credential of its own for talking to WP Octo, issued once and replaced on request * **Added** – auth: WP Octo's credential can travel in a header of its own, so a plugin that owns the Authorization header no longer stands in the way * **Improved** – updates: A last-resort WP Octo address is used when the remembered one has failed for a day * **Fixed** – restore: A restore keeps the site's connection to WP Octo and the work in flight instead of rolling them back to the backup's day * **Fixed** – backups: A scheduled backup that fails while continuing on cron is reported instead of stopping silently * **Security** – backups: The site's credentials toward WP Octo are never written into a backup ## 2.2.3 – 07-09-2026 [#223--07-09-2026] * **Fixed** – backup: a forced restart whose cleanup fails unexpectedly no longer leaves the site locked for other operations ## 2.2.2 – 07-09-2026 [#222--07-09-2026] * **Fixed** – backup: a forced restart clears the previous run even when its manifest is missing or unreadable * **Fixed** – backup: a forced restart that cannot remove the previous files is refused instead of starting a new backup on top of them ## 2.2.1 – 07-09-2026 [#221--07-09-2026] * **Fixed** – backup: a forced restart of a backup the site already knows clears the previous run before starting over * **Fixed** – restore: a backup that never completed, or whose manifest lists no files, is refused instead of restored from whatever is in its folder * **Fixed** – backup: downloading a backup chunk no longer hangs on sites where another plugin keeps an output buffer open ## 2.2.0 – 07-09-2026 [#220--07-09-2026] * **Added** – Backups: Brings a backup that only exists in external storage back onto the site before restoring it * **Fixed** – Restore: Refuses to restore a backup whose files are not on the site instead of restoring what happens to be there * **Improved** – Backups: Reports whether a backup's files are actually on the site * **Fixed** – Backups: Keeps a backup listed after its local copy is released * **Fixed** – Backups: Starting a backup twice no longer restarts one that is still running * **Fixed** – Backups: Sends large backup files whole instead of an empty response ## 2.1.9 – 06-09-2026 [#219--06-09-2026] * **Fixed** – Updates: Keeps the site available while WP Octo updates itself * **Fixed** – Updates: Refuses to start on an incomplete installation instead of breaking the site * **Fixed** – WordPress updates: Reports a successful WordPress core update as successful instead of failed * **Fixed** – WordPress updates: Reads the WordPress version and the available update reliably ## 2.1.8 – 06-09-2026 [#218--06-09-2026] * **Fixed** – Maintenance mode: Stops holding a site after four hours when an update round cannot finish * **Security** – Maintenance mode: Lets only the WP Octo REST routes through and no longer trusts a spoofable request header * **Improved** – Maintenance mode: Stages, verifies and atomically replaces the maintenance flag, and refuses unsafe filesystem transports * **Fixed** – Health check: Recognises active, expired, legacy and unknown maintenance files ## 2.1.7 – 05-09-2026 [#217--05-09-2026] * **Security** – REST API: Prevents WordPress page caches from serving an authenticated response to anyone ## 2.1.6 – 05-09-2026 [#216--05-09-2026] * **Security** – REST API: Prevents shared caches from exposing authenticated WP Octo responses ## 2.1.5 – 04-09-2026 [#215--04-09-2026] * **Fixed** – recovery-enrollment: Safely pairs MU recovery credentials between WP Octo and the worker ## 2.1.4 – 04-09-2026 [#214--04-09-2026] * **Fixed** – delete-plugin: Prevents WP Octo from deleting itself through the worker API ## 2.1.3 – 04-09-2026 [#213--04-09-2026] * **Added** – Recovery: Restores WP Octo from the platform when the plugin itself cannot load * **Added** – Recovery: Starts and verifies a rollback while the plugin is unavailable * **Security** – Recovery: Closes out-of-band enrolment so only the paired platform can recover a site ## 2.1.2 – 04-09-2026 [#212--04-09-2026] * **Fixed** – Restore: Restores a partial backup instead of refusing incomplete component sets * **Fixed** – Update rollback: Runs the rollback that previously never executed * **Fixed** – Plugin backup: Authenticates plugin backup over the REST API * **Fixed** – Maintenance mode: Authenticates maintenance mode over the REST API ## 2.1.1 – 23-08-2026 [#211--23-08-2026] * **Improved** – Release build: Produces an identical zip and checksum from the same source ## 2.1.0 – 23-08-2026 [#210--23-08-2026] * **Added** – Self-update: Installs a release when WP Octo says so, not on the next admin page load * **Added** – Self-update: Keeps a rollback copy outside the plugin directory before every update * **Added** – Safe mode: Restores the previous version without loading the plugin * **Added** – Self-update: Verifies the SHA-256 of a package before unpacking it * **Added** – Self-update: Reports what is installing, what failed and whether a rollback is available * **Improved** – Update check: Reports that an update exists without installing it * **Improved** – Self-update: Asks WP Octo what this site may install instead of reading one shared file * **Improved** – Self-update: Learns the platform address from the platform's own authenticated calls * **Improved** – Self-update: Installs through the WordPress upgrader so hosts without direct file access work * **Fixed** – Self-update: Restores the previous copy when an update fails instead of leaving no plugin directory * **Fixed** – Self-update: Keeps file permissions across a rollback * **Security** – Self-update: Refuses any update not confirmed by WP Octo for this site at that moment * **Security** – Self-update: Accepts packages only over https and never from inside the site's own network ## 2.0.0 – 23-08-2026 [#200--23-08-2026] * **Added** – Analytics: Reports visitors first-party and cookieless, with no cookie banner needed * **Added** – Activity log: Records what happened on the site, grouped per request, with export and notifications * **Added** – Error log: Separates broken links on your own pages from bad inbound links and scanner traffic * **Added** – Error log: Creates a redirect straight from a failing request * **Added** – Email log: Shows what happened to each message, with delivery diagnostics and retention limits * **Added** – Email log: Checks whether the sending domain is set up to be believed * **Added** – Login attempts: Lists which usernames were tried, whether they exist, and their role and two-factor state * **Added** – Login attempts: Allows, blocks and exports attempts, individually or in bulk * **Added** – Danger Zone: Resets settings or removes WP Octo data, taking a recovery snapshot first * **Added** – Security settings: Locks out repeated failed logins and sets how long a session lasts * **Added** – Security settings: Checks file integrity and offers a read-only mode that closes the front end * **Added** – Update control: Holds individual plugins and themes back from updates * **Added** – Overview: Shows what needs doing, recent activity and trends on one screen * **Added** – Notes: Records a note against a plugin or a theme * **Added** – Backups: Backs up a single plugin, a single theme, or core on its own * **Added** – Safe mode: Provides standalone entry points that keep working when the site is broken * **Added** – Translations: Ships in English and fully translated into Dutch * **Improved** – Authentication: Accepts the workspace token as a Bearer credential and nothing else * **Improved** – Magic login: Uses a one-time ticket valid for sixty seconds instead of a credential in the address * **Improved** – Backups: Stores backups in a directory whose name carries a secret * **Improved** – Backups: Clears an update only when the backup actually covers what is about to change * **Improved** – Email log: Moves the log out of the options table * **Improved** – Update machinery: Stops loading on every front-end page view * **Improved** – Backups: Opens the file tree one folder at a time instead of the whole backup at once * **Improved** – Backups: Moves backup history into the activity log * **Fixed** – Restore: Keeps the workspace token, which a restore used to wipe and leave the site unreachable * **Fixed** – Plugin update: Deactivates a plugin whose update failed instead of deleting it * **Fixed** – Restore: Cancels a restore without a fatal error * **Fixed** – Safe mode: Repairs every safe mode entry point, all of which were dead * **Fixed** – Backups: Stops recording a busy worker as a failed backup or restore * **Fixed** – Restore: Completes across foreign keys and removes its temporary tables * **Fixed** – Restore: Runs on hosts without the zip extension * **Fixed** – Backups: Stops reporting an incomplete backup as complete * **Fixed** – Translations: Loads the translations, which were never loaded * **Fixed** – Email log: Stops autoloading the log on every request, front end included * **Fixed** – Email log: Caps a stored message body at 256 KB * **Fixed** – Deactivation: Removes the seven scheduled tasks that were left behind * **Fixed** – Retention: Ages records out against the correct clock * **Fixed** – Assets: Restores cache busting, which the version stripper disabled * **Security** – Plugin API: Closes an endpoint that accepted a self-chosen token without authentication * **Security** – File handling: Closes an unauthenticated entry point that could write a file anywhere on the site * **Security** – Email log: Requires a login to read the log * **Security** – Backups: Requires authorisation to download a backup * **Security** – Authentication: Compares tokens once, in constant time, instead of four times side by side * **Security** – Validation: Rejects a trailing newline that could carry past an identifier check * **Security** – Settings: Filters a client-supplied value before displaying it * **Security** – Codebase: Removes eval() and a page that loaded code from a CDN * **Removed** – Authentication: Removes the Octo-Token header and the octo-token query parameter * **Removed** – Configuration: Removes the per-site token in config.php, which every update deleted * **Removed** – Codebase: Removes ConfigService, TokenService and the API client that fetched the token * **Removed** – Codebase: Removes tempauthfix5.json, which handed the site token to anyone who asked --- # Connection URL: https://wpocto.com/docs/worker/connection The one credential that pairs a site with its workspace, and the two directions the site and the platform talk in. ## One credential [#one-credential] A managed site accepts exactly one credential: the **workspace token**, a secret that belongs to the workspace and is installed on every site in it. The platform presents it on every call to the site, and the worker checks it and refuses anything else. There is no per-site password, no API key on the site, and no login through WordPress's own cookies. Since worker 2.3.0 the site also holds a **credential of its own** for the calls *it* makes to the platform, issued by the platform the first time the site reports in and replaced on request. Work the platform hands a site — a backup, an upload to storage, a restore, its own update — is offered only to a site that identified itself with that credential, and every such instruction is signed and valid once. Neither credential is written into a backup, so a restore does not roll the site's connection back to the backup's day. Keep the two credentials WP Octo has apart: | | What it opens | Where it belongs | | ------------------- | ------------------------------ | ----------------- | | **Workspace token** | the worker on a managed site | on the sites | | **API key** | the platform's own [API](/api) | in an integration | Putting an API key on a site would hand the platform to whoever compromises that site. The worker never asks for one and has nowhere to put it. ## Two directions [#two-directions] **The platform calls the site** to read its inventory, run an update, take or restore a backup, run a health check and update the worker. This is what a host firewall refuses when it decides the platform is a bot — [Hosting compatibility](/worker/hosting-compatibility). **The site calls the platform** on its own schedule: every fifteen minutes by default, sooner when there is work, and less often when the platform asks it to wait. It reports its worker version and environment, any dataset that changed since it last reported, and what happened on the site; the platform answers with what it wants to see in full, any work it has for the site, and when to call next. A site that cannot be reached by the platform therefore still keeps its data current and still does its work, at the cadence its own WP-Cron gives it. ## What a host has to allow [#what-a-host-has-to-allow] * **Outbound HTTPS** from the site to `wpocto.com`. This is the one connection nothing works without. * **The platform's calls** to the site's own address. A firewall or bot protection that refuses them is reported on the site's Health page with the provider named and the address to allow; the site keeps reporting in the meantime. ## A header of its own [#a-header-of-its-own] Since worker 2.3.0 the platform sends its credential in a header of its own rather than the standard `Authorization` header, so that a plugin that owns that header — a JWT authentication plugin — or a host that strips it no longer stands in the way. Older workers are sent the standard header. There is nothing to configure on either side. ## Redirects [#redirects] The platform's authenticated calls never follow a redirect. A site that redirects — to `https`, to `www`, to another path — is refused when it is added to the dashboard, and a site that starts redirecting later shows as unreachable with the redirect as the cause. Enter the address the site actually answers on. ## Caching in front of the site [#caching-in-front-of-the-site] An authenticated answer must never be stored by a page cache and handed to the next caller. The worker marks every answer to the platform as not cacheable and, on hosts running LiteSpeed Cache — which caches the WordPress REST API by default and ignores the standard headers — tells the cache plugin directly not to store it. --- # Hosting compatibility URL: https://wpocto.com/docs/worker/hosting-compatibility Firewalls, bot protection and authentication plugins that interfere with the platform's calls, and what still works when they do. ## Firewalls that answer for the site [#firewalls-that-answer-for-the-site] Imunify360, Sucuri, Cloudflare and Wordfence all sit between the platform and the site and decide, per request, whether the caller looks like a bot. The platform's calls are not a browser — no cookies, no JavaScript, a fixed client — and any of these may refuse them, sometimes only after a period of normal traffic, sometimes only for one call in ten. The refusal takes different shapes — a challenge page, a block page, a plain refusal — and the platform recognises each of them and reports the site as **blocked by a firewall** with the provider named, rather than as "inactive". A page that says "one moment, please" is not the site, and the platform does not read it as one. ## What still works on a blocked site [#what-still-works-on-a-blocked-site] Since worker 2.3.0 a site the platform cannot call still: * **reports its state** — worker version, environment, plugins, themes, users, core, health, backups — on its own schedule; * **takes its work** — a backup, an upload to storage, a sync — from the platform's answer to that report and runs it on its own WP-Cron; * **records what happened** and sends it on the next contact. What does *not* work on a blocked site is anything the platform has to drive step by step from its side: an update round, a restore, a worker update pushed by the platform. The site's **Health** page shows both directions separately, so a site that is blocked from the platform's side and fresh from its own reads as exactly that. ## What a person has to do [#what-a-person-has-to-do] The platform never tries to get past a firewall. When it finds one it writes an instruction on the site's Health page: the provider it recognised, the platform's address, and where on that provider that address is allowed. Allowing it restores the connection; the platform notices on its next check, marks the site recovered, and — if the site's worker is behind the current release — starts a rollout for that one site. It is set by a person, and the next change on either side silently invalidates it: the platform moving to a new address, the site moving to a new host, the host reinstalling its firewall. Treat it as the workaround it is. The structural answer is the site's own reporting, which needs nothing on the host — and where a site must take an update the platform cannot push, the worker can still install a release the platform has approved for it through WordPress's own updater. ## Authentication plugins [#authentication-plugins] A JWT authentication plugin owns the `Authorization` header on the WordPress REST API and answers a bearer token it does not recognise before the worker runs, with an error of its own such as *Wrong number of segments*. The platform reports this as **authentication failed** and names the plugin's involvement. Two ways out: exclude the `wpocto/v1` namespace in the plugin's settings, where it offers that; or run worker 2.3.0 or later, which reads the platform's own header and leaves `Authorization` to the plugin. The second needs the site to have reached 2.3.0 — by rollout where the platform can reach it, or by uploading the zip once where it cannot. The namespace is the one the site's **Health** page names when the platform finds such a plugin in the way; it is written here so a host administrator can act on it without the page in front of them. ## Caches [#caches] LiteSpeed Cache caches the WordPress REST API by default and ignores the standard `Cache-Control: no-store` header. The worker uses the plugin's own settings to mark its answers as not cacheable, so an authenticated answer is never served to the next caller. Other page caches honour the standard headers the worker sets. A cache that still answers for the site is visible in the dashboard as data that does not change when it should; exclude `wp-json/wpocto/v1` in the cache's settings. Where the platform itself finds a cache serving the worker's answers, the site's **Health** page names that path as the thing to exclude. ## Hosts known to need attention [#hosts-known-to-need-attention] Rather than a list of hosting companies — which is wrong the day it is written — the platform classifies every site it cannot reach by what it found, and the classification is what to act on. [Troubleshooting](/worker/troubleshooting) lists each state. --- # Worker plugin overview URL: https://wpocto.com/docs/worker What the WP Octo plugin does on a managed site, and how it relates to the platform. The worker is the half of WP Octo that lives on the site. It is an ordinary WordPress plugin, named **WP Octo** in the plugin list, and it exists so the platform can look after the site from one place. The platform decides *what* should happen; the worker does it *on the site*, in steps small enough for shared hosting. ## What it does on the site [#what-it-does-on-the-site] * **Backups and restores**, in steps that survive a timeout, with the pieces uploaded to storage and verified after upload. * **Core, plugin and theme updates**, run as a round with a backup taken first and the site's pages checked afterwards. * **An activity log** recording who changed what and when. * **An email log** showing what was sent, whether it arrived, and what went wrong when it did not. * **Login attempts**, with the tried names checked against real accounts. * **Analytics** without cookies and without a third party. * **A log of failed requests** — broken links, blocked requests and server errors — with redirects made straight from the list. * **Reporting to the platform** on its own schedule, so the platform's picture of the site stays current even when a host firewall keeps the platform from calling in. * **Keeping itself up to date**, with a rollback copy kept outside the plugin folder, when the platform says a release is available for the site. All of it is driven by, and reported to, the platform. The plugin does nothing on its own initiative beyond its own scheduled reporting and the housekeeping it was given. ## Its own screens [#its-own-screens] The plugin adds an **Octo Tools** menu to the site's admin. [Installation](/worker/installation) names the screen where the workspace token is pasted, and [Troubleshooting](/worker/troubleshooting) the logs to read. Everything the platform does on the site is visible in the activity log, with the platform named as the actor. ## What it needs [#what-it-needs] A current release on PHP 7.4 or later and WordPress 5.2 or later, with 30 seconds of execution time and 128 MB of memory as the floor it is designed for. It never assumes WP-CLI, shell access or a database console. [Requirements and hosting](/worker/requirements-and-hosting) has the details, and [Hosting compatibility](/worker/hosting-compatibility) covers the firewalls and caches that get in the way. ## How it talks to the platform [#how-it-talks-to-the-platform] In two directions, over HTTPS: the platform calls the site to read its inventory, run an update, take or restore a backup, or update the worker; and the site calls the platform on its own schedule to report its state and pick up work. One credential, the **workspace token**, pairs the two. [Connection](/worker/connection) explains it. --- # Installation URL: https://wpocto.com/docs/worker/installation Installing the worker plugin on a site and pairing it with a workspace. ## Get the plugin [#get-the-plugin] The current release of the worker is offered from the dashboard: open the site under **Websites**, choose **Connect Website**, and use **Download Plugin**. The same page lists the steps below. The zip contains the plugin only. It holds no credential, no storage key and nothing that is specific to a site; the pairing happens after activation. ## Install and activate [#install-and-activate] In the site's WordPress admin: **Plugins → Add New → Upload Plugin**, choose the zip, install, activate. The plugin adds an **Octo Tools** menu with its screens. Nothing is sent anywhere yet. Until the site holds a workspace token it answers every platform call with a refusal, which is the correct state for a site that is not paired. ## Pair the site [#pair-the-site] The site pairs with a workspace through the **workspace token**, and it gets there in one of two ways: | | When | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **The platform installs it** | The site was added to the dashboard and the platform can reach it. The platform places the token on the site and checks that the site accepts it — and that it refuses a wrong one — before it is trusted. | | **You paste it** | Open **Octo Tools → Settings → General** on the site and paste the workspace token from **Workspace settings** in the dashboard. This is the route for a site set up on its own, or for a host whose firewall keeps the platform from reaching the site. | Either way the site ends up holding one credential, checked on every call. ## Confirm [#confirm] In the dashboard, open the site's **Health** page and run a health check. A paired site answers with its worker version and its status becomes *active*. Within a few minutes the site's plugins, themes, users and core version appear on their pages, and the site makes its first call to the platform. If the health check names a cause instead — a firewall answering for the site, a plugin that took the credential before the worker saw it, a certificate problem — [Troubleshooting](/worker/troubleshooting) lists what each means and what to change. ## Updating the plugin later [#updating-the-plugin-later] You do not upload a new zip for a new version. The platform tells each site which release is available for it, in stages across the fleet, and the worker installs it with a rollback copy. [Plugin updates](/worker/updates) describes it. Uploading a newer zip by hand still works and is sometimes the only way onto a site the platform cannot reach; the site reports the version it runs on its next contact. --- # Recovery URL: https://wpocto.com/docs/worker/recovery What happens when an update breaks the plugin, when the platform is not there, and what a person has to do. ## Two things that can go wrong [#two-things-that-can-go-wrong] * **The plugin cannot load.** A plugin update — including the worker's own — leaves the site failing on load, and the worker's normal way of answering the platform never gets a chance to run. * **The platform is not there.** A round that put the site into maintenance mode cannot take it back out because the platform, or the connection to the site, is gone. The worker is built so that neither strands the site. ## When the plugin cannot load [#when-the-plugin-cannot-load] The worker ships with recovery files beside its main file that work without loading the plugin — or any plugin at all. Through them the platform can put the previous worker version back from its rollback copy, undo what an update round changed, and lift maintenance mode, on a site whose plugin layer is broken. Since 2.1.3 a small loader installed alongside the plugin lets the platform restore the worker even when the plugin's own files are damaged; it acts only for the platform the site is paired with, and only when that platform asks. A security scanner or a cleanup that flags "unused PHP files in the plugin root" and removes them takes the site's recovery with it. Leave them in place. What recovery cannot do is bring back a plugin directory that has been deleted entirely, because the recovery files went with it. Such a site runs unmanaged, which is safe, and the platform reports it as unreachable; uploading the current zip brings it back. ## Maintenance mode lifts itself [#maintenance-mode-lifts-itself] An update round puts the site into maintenance mode, and the platform is what takes it back out. So the worker's own maintenance flag carries an expiry — never more than four hours — after which the site comes back on its own, whatever happened to the round. Before worker 2.1.8 a site whose round never finished stayed dark until a person noticed; the platform now refuses to start a round on a worker older than that. ## The worker's own rollback [#the-workers-own-rollback] A self-update keeps the previous version outside the plugin folder, three copies deep, and rolls back on any failure it detects itself. The platform checks the installed version afterwards by asking the site, and orders a rollback when the answer is wrong. ## What the platform does for a site it cannot reach [#what-the-platform-does-for-a-site-it-cannot-reach] Nothing to the site. It records the cause, writes an instruction for a person where one is needed, keeps asking on a schedule that widens with each failure — and when the site is reachable again, marks it recovered and brings its worker up to the current release. [Hosting compatibility](/worker/hosting-compatibility) covers the firewall case; [Troubleshooting](/worker/troubleshooting) lists the states. ## What a person has to do [#what-a-person-has-to-do] * **A broken plugin the platform could not repair**, or a site the platform cannot reach: upload the current zip over it through **Plugins → Add New → Upload Plugin**. The site reports the version on its next contact. * **A plugin directory that is gone**: install the plugin again and paste the workspace token — [Installation](/worker/installation). * **A maintenance page that outlives four hours** is not the worker's. Look at the host and at other plugins. --- # Requirements and hosting URL: https://wpocto.com/docs/worker/requirements-and-hosting What the worker is built to run on, and the limits of shared hosting it is designed around. ## Supported environments [#supported-environments] | | | | ------------- | ------------------------------------------------------------------------------------------------ | | PHP | 7.4 or later; every version from 7.4 to 8.5 is in the plugin's own test matrix. | | WordPress | 5.2 or later declared; 5.9 and later are the versions the plugin is booted against in its tests. | | Web server | Apache, LiteSpeed or nginx; anything that serves WordPress. | | WP-CLI, shell | Not needed and never assumed. | ## The floor: 30 seconds and 128 MB [#the-floor-30-seconds-and-128-mb] Shared hosting commonly gives a PHP request thirty seconds and 128 MB, and stops it when either runs out. The worker is written for that floor: * **A backup is a sequence of steps**, each small enough to finish inside the limit, each recorded before the next begins. If a step is cut off, the next call continues from the last recorded one. The pieces are read back before the backup is called complete. * **A restore, and a download from external storage**, work the same way, one piece at a time. * **An update round** is driven from the platform one operation at a time: back up the plugins, update one, verify, on to the next. * **The site calls the platform** on WP-Cron, and the work it picks up there is stepped on WP-Cron too. More execution time and memory make all of it faster; none of it depends on more. ## What WP-Cron means here [#what-wp-cron-means-here] WordPress's scheduler runs when a page is requested. The worker uses it for the parts of its work that happen between calls from the platform: continuing a backup, running a scheduled one, pruning old ones, reporting to the platform. On a busy site that is effectively continuous; on a quiet one it runs when a visitor or the platform arrives. A site with `DISABLE_WP_CRON` and no system cron in its place does that work only when something calls it. The platform shows the age of each dataset rather than guessing, so such a site is visible as one whose data is older than it should be. ## Storage on the site [#storage-on-the-site] Backups the site makes are written under `wp-content/backups/`, in a directory whose name carries a secret of the site's own, one folder per backup. The size of a full backup is roughly the size of the site. A storage policy of *external* has the platform release the site's copy once the copy in object storage is verified, so the site holds a backup only for as long as the upload takes. The activity and email logs are daily files in the same area; the error log and analytics are tables of the plugin's own. ## Outbound HTTPS is the one hard dependency [#outbound-https-is-the-one-hard-dependency] The site must be able to open an HTTPS connection to the platform. That is what registration, reporting, picking up work and update checks all use, and it is the one channel that survives a host firewall blocking the platform's calls. A site that cannot make outbound HTTPS calls at all — a rare host setting — can be managed only when the platform can reach it, and then only from the platform's side. ## Limits that come from the host [#limits-that-come-from-the-host] * **A firewall or bot protection** in front of the site may refuse the platform's calls. The site keeps working on its own schedule; see [Hosting compatibility](/worker/hosting-compatibility). * **A page cache** that caches the WordPress REST API is told not to on the worker's answers; see [Connection](/worker/connection). * **A host that strips the `Authorization` header** is handled by the worker's own header since 2.3.0. * **A host that blocks outbound connections** to anything but a list of addresses needs `wpocto.com` on that list. --- # What the plugin stores and trusts URL: https://wpocto.com/docs/worker/security What the worker keeps on the site, what it trusts, and what it refuses. ## What the site trusts [#what-the-site-trusts] Exactly one thing on its own side: a caller presenting the workspace token. For the calls it makes itself, since 2.3.0, it presents a credential of its own, issued by the platform and replaced on request, and the instructions it accepts in the answer are signed by the platform and valid once. Everything the platform may do to the site — read its inventory, run an update, take and restore a backup, replace the worker, log an administrator in — is behind that one check. There is no second credential, no list of allowed addresses on the site's side, and nothing that answers an anonymous caller with anything but a refusal. The login the dashboard offers is the one place a platform call becomes a WordPress session: the site issues a ticket that the browser then redeems, valid once and for one minute. ## What the site stores [#what-the-site-stores] * **The workspace token**, and since 2.3.0 the site's own credential beside it. Since 2.3.0 neither is written into a backup. * **The platform's address**, for the calls the site makes. * **Backups**, under `wp-content/backups/` in a directory whose name carries a secret of the site's own, so that nobody can guess the path; released when the storage policy says so. * **Logs** — activity and email as daily files, errors and analytics in tables of the plugin's own, login attempts. Analytics stores no cookie; visitors are hashed with a per-site salt. The site never holds an object-storage credential. When a backup is uploaded, or downloaded again for a restore, the platform hands the site links that read or write one file for a limited time. The site never sees a key. ## What the site refuses [#what-the-site-refuses] * **Anonymous callers**, and callers with a wrong token. * **Being cached.** Every answer to the platform is marked not cacheable, and LiteSpeed Cache is told directly. * **A release it was not given.** The worker installs only what the platform released to this site, checksum verified, and refuses when it cannot ask. * **A restore it cannot do.** A restore from a copy on the site that is not wholly there is refused with a cause, rather than restoring what happens to be in the directory. ## What the platform refuses on the site's behalf [#what-the-platform-refuses-on-the-sites-behalf] * **A site that redirects** is not accepted, because a redirect would strip the credential from the platform's calls. * **Following a redirect** on an authenticated call, ever. * **A firewall's page** in place of the site's answer, and a report of success the site itself contradicts. * **Trusting a site with a credential** before the site has refused a wrong one. ## Reporting a problem [#reporting-a-problem] If you find something in the worker that this page says should not be possible, report it privately as described under [Reporting a vulnerability](/application/security/reporting). --- # Troubleshooting the worker URL: https://wpocto.com/docs/worker/troubleshooting The states the platform reports about a worker it cannot reach, what each means, and what to change. The platform never reports a site as merely "inactive". Every time it cannot reach a worker it establishes where the connection broke — does the site's name resolve, does the site answer, does WordPress answer, is the plugin active and complete, does it accept the credential — and reports that. The site's **Health** page shows it, with an instruction where a person is needed. | State | What was found | What to do | | ------------------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **DNS error** | The site's name does not resolve. | Check the domain's DNS; check the address the site was added with. | | **SSL error** | The certificate is invalid, expired, or for another name. | Renew or correct the certificate on the host. | | **Timeout** | The site did not answer in time. | Usually the host; the platform asks again on a widening schedule. Persistent timeouts are a host performance problem. | | **Connection refused** | Nothing answered on the port. | The web server is down or the address is wrong. | | **Blocked by a firewall** | A firewall (the provider is named) answered instead of the site. | Allow the platform's address as instructed on the Health page. Since 2.3.0 the site keeps reporting and taking its work meanwhile. | | **Plugin inactive** | WordPress answers, but the worker is not active. | Activate the worker, or reinstall it if it is gone. | | **Route missing** | The worker is active but incomplete. | A partial install or an old version; reinstall the current release. | | **Authentication failed** | The site refused the workspace token — and whether another plugin took the credential first is noted. | If a JWT plugin is involved: exclude the worker's `wpocto/v1` namespace in that plugin, or bring the site to 2.3.0. Otherwise the token on the site is not the workspace's; paste the current one. | | **Worker error** | A PHP error on the site. | Read the error the page shows; an error in the worker itself is recovered as [Recovery](/worker/recovery) describes. | | **HTTP error** | Another HTTP status that is not a WordPress answer. | Read the status; often a host's maintenance or error page. | | **Unknown** | A shape none of the above fit. | Report it; the platform records what it saw. | Where a state needs something changed on the host — an address allowed in a firewall, the `wpocto/v1` namespace excluded from a JWT plugin, a path excluded from a cache — the Health page writes the instruction with what it found, and the table above says the same thing so it can be acted on without the page in front of you. A **temporary** cause — timeout, refused, an HTTP error, unknown — is asked again after 5, 15, 30, 60, 120 and then every 360 minutes; a **structural** one — firewall, credential, plugin, certificate, DNS — after 1, 3, 6, 12 and then every 24 hours. Always asked again: the thing that fixes a structural cause happens on the site without telling the platform. Every call the site makes to the platform also brings the next check forward. ## The site is reachable but its data is old [#the-site-is-reachable-but-its-data-is-old] The Health page shows each dataset with its age and the channel it last came over. Data that ages while the site is reachable means the platform's read of that dataset failed; the failure is recorded and the age shown rather than a fresher time invented. Data that ages while the site is *not* reachable means the site's own calls have stopped: its WP-Cron is not running, or its outbound HTTPS is blocked. Load a page on the site, or check whether the host disabled WP-Cron. ## Another operation is running [#another-operation-is-running] The site refuses a second operation while a backup, a restore or a worker update runs, and says so. The platform waits and asks again; nothing is needed from you. A lock left by a crashed process expires after fifteen minutes. ## A backup stops at a step [#a-backup-stops-at-a-step] The worker records each step; the platform continues it on the next call and decides failure only from the site's own reported progress — no change for a set time, or an operation older than its ceiling. A backup that is slow is not a backup that failed. If a site's backups never complete, the usual cause is a host that kills the process before a single step finishes; the step size adapts, but a host that gives a request a few seconds cannot back up a large site. ## The plugin fails on load [#the-plugin-fails-on-load] If the site is down because of the worker, the platform puts the previous version back through the worker's recovery files, which work without loading any plugin. Uploading the current zip over the broken install is the manual equivalent. [Recovery](/worker/recovery). ## Where to look on the site [#where-to-look-on-the-site] **Octo Tools → Error log** shows the errors the site served, with per-request hits; **Activity log** shows who changed what, with the platform's actions named as such; the worker's own debug log is under `wp-content/uploads/wpocto-log/`. The platform's actions on the site appear in the dashboard under the site's activity and update rounds. --- # Plugin updates URL: https://wpocto.com/docs/worker/updates How a new worker release reaches a site, and how the site protects itself while installing it. ## The platform decides, per site [#the-platform-decides-per-site] A worker release is published once, as a zip with a recorded checksum. The platform rolls it out in **stages**: a small group of sites first, then larger ones, each stage waiting a set time after the previous one settled before it starts. A stage that produces failures stops the rollout. A site therefore never installs a release just because it exists. It installs the release the platform has released *to it*. ## What the worker does [#what-the-worker-does] On the platform's instruction the worker: 1. **Checks** that the release can be fetched and written, and that nothing else — a backup, a restore — is running on the site. 2. **Installs** — downloads the zip, verifies its checksum, keeps a rollback copy of the running version **outside** the plugin folder, and swaps the plugin under maintenance mode so a visitor is never served a half-replaced plugin. On hosts where PHP cannot write the plugin directory directly, it installs through WordPress's own upgrader. 3. **Reports** the version now running, which the platform confirms by asking the site again rather than trusting the report. 4. **Rolls back** on any failure, from the copy it kept, and says so. The rollback also works when the new version cannot load at all — [Recovery](/worker/recovery). ## The worker asks before it installs [#the-worker-asks-before-it-installs] Before installing anything the worker asks the platform whether this release is for this site, and installs nothing when it gets no clear answer. The same applies to WordPress's own updater: a site the platform cannot call can still pull a release through **Plugins → Updates**, but only one the platform has approved for it. ## A site that missed a rollout [#a-site-that-missed-a-rollout] A site that was unreachable during a rollout — behind a firewall, say — is not left behind. The first time the platform reaches it again and finds it below the current release, it starts a rollout for that one site immediately, with the same checks, install, confirmation and rollback. ## What you see in the dashboard [#what-you-see-in-the-dashboard] The site's header shows the version it reported last. Where a decision depends on the version, the platform asks the site rather than trusting the record. In the fleet's activity you see that a worker was updated. ## Updating by hand [#updating-by-hand] Uploading a newer zip through WordPress's plugin screen works and is the route for a site the platform cannot reach and that cannot pull through the updater either. The site reports the new version on its next contact, and the platform's record follows the site. --- # Versions URL: https://wpocto.com/docs/worker/versions Which worker versions the application works with, and what changed between them that a site can notice. ## Worker versions the application supports [#worker-versions-the-application-supports] The application works with every worker version from 2.0.0 on, choosing per site what that version understands. Four thresholds matter: | From worker | What changes | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **2.1.0** | The platform decides per site which release it installs, and the worker keeps a rollback copy of itself. A site on an older worker is brought to this line by uploading the zip once. | | **2.1.8** | The site's own maintenance flag expires on its own. **The application refuses to start an update round on a worker older than this**, because a round that cannot finish would otherwise hold the site dark. | | **2.2.0** | Restore from a backup that exists only in external storage. An older worker cannot, and such a restore is reported as unsupported rather than as a missing backup. | | **2.3.0** | The site reports and takes its work on its own schedule; the platform's credential travels in a header of its own; a credential per site; signed instructions. A site below 2.3.0 keeps working as long as the platform can reach it. | The dashboard shows each site's worker version, and a site behind the current stable release is brought up to it by rollout when the platform can reach it — [Plugin updates](/worker/updates). ## What a version number means [#what-a-version-number-means] A worker release goes through release candidates — `2.3.0-rc.1`, `-rc.2` — on test sites before it is published as stable, and only the stable version is listed in the [changelog](/worker/changelog) and rolled out. A published version is never changed; the next change is a new version. A **patch** (`2.3.0` → `2.3.1`) is a compatible fix; a **minor** (`2.3` → `2.4`) is a compatible set of user-relevant features. ## Breaking changes, by kind [#breaking-changes-by-kind] **For a site** * 2.1.8: sites below this version are excluded from scheduled update rounds until updated. * 2.2.0: needed to restore from a backup whose only copy is in external storage. **For an integration** * The API is versioned under `/api/v1`. Nothing in it has been removed — [API → Changes](/api/changes). **For this documentation** * Worker versions before 2.0.0 are not described here; the records that would support such a description do not exist. --- # API reference URL: https://wpocto.com/docs/api/reference Every endpoint of the WP Octo HTTP API, generated from its OpenAPI description (version 1). {/* Generated by scripts/generate-openapi-docs.ts from the exported OpenAPI document. Do not edit by hand. */} The reference is generated from the same OpenAPI document the application exports from its routes, form requests and resources, so it describes the API as it is deployed. Every page has an interactive playground; send your own workspace API key as the bearer token, never one that belongs to someone else. --- # Add your first website URL: https://wpocto.com/docs/application/getting-started/add-your-first-website Register a site in the dashboard so the platform knows it and the worker plugin can connect to it. ### Create the client [#create-the-client] Go to **Clients** and add the customer the site belongs to, with a name and whether they should receive the update emails. A client is where a site hangs; you can add several sites to one client. ### Have a package ready [#have-a-package-ready] Go to **Packages** and make sure there is a package with the update frequency, backup interval, storage policy and monitoring interval you want for this site. One package serves many sites, so this is usually a one-time step. ### Add the website [#add-the-website] Go to **Websites → Create** and fill in: * **Name** — how the site appears in lists. * **URL** — the address the site answers on, exactly. The platform checks that the address does not redirect before it accepts it; a `www` or `https` redirect has to be resolved first. * **Client** and **Package**. * **Tags**, if you use them to group sites. * **Backup** — the package's interval and storage policy apply by default; override them here when this site needs something else. * **Monitoring** — whether the site's pages are monitored and how often. * **Update weekdays** — the days on which scheduled update rounds may run for this site. Save. The site now exists on the platform, with no worker connected yet. ### Install the worker plugin on the site [#install-the-worker-plugin-on-the-site] Follow [Install the worker](/application/getting-started/install-the-worker). Until the plugin is installed and connected, the site shows as not yet reporting. ## After the site connects [#after-the-site-connects] The platform reads the site's plugins, themes, users and WordPress core, checks whether its pages answer, and starts monitoring on the package's interval. The site's **Health** page shows the connection, when each dataset was last received and over which channel, and what — if anything — needs attention. [First checks](/application/getting-started/first-checks) walks through it. --- # First checks URL: https://wpocto.com/docs/application/getting-started/first-checks What to look at once a site is connected, and what a healthy site looks like in the dashboard. ## The site's overview [#the-sites-overview] Open the site from **Websites**. The header shows the site's worker version, when it last reported, and its status. Below it, the pages of the site: Health, Plugins, Themes, Users, Core, Backups, Restores, Update rounds, Monitoring, Regression, Reports, Notes. ## Health [#health] The **Health** page is the place to confirm a new connection: * **Connection** — whether the platform can reach the site (inbound), and when the site last called the platform (outbound). A site that is reachable one way but not the other is still fine; the page says which. * **Data** — one row per dataset the platform holds about the site: plugins, themes, users, core, health, backups, worker, environment. Each row says when it was last received and over which channel. Every row should read *fresh* shortly after connecting; a row that stays *unknown* means that dataset has never arrived. * **Work waiting for the site** — instructions the platform has handed the site that it has not finished yet. Normally empty. * **What needs attention** — the causes the platform found and, where it can say, what a person has to do. Use **Run health check** to ask again immediately. ## Plugins, themes, users, core [#plugins-themes-users-core] Each page lists what the site reported, with a **Sync** action to ask again. From here plugins and themes are activated, deactivated, updated and deleted, and WordPress core updated — one at a time, as opposed to the scheduled [update round](/application/updates) that does them together with a backup and checks. ## Monitoring [#monitoring] Monitoring starts automatically on the package's interval for the site's home page and any further pages you add under **Regression**. The **Monitoring** page shows the checks and their log for the last ninety days. ## Backups [#backups] If the package schedules backups, the first one lands in the night window after the site was added. Take one by hand from **Backups** to see the whole cycle — the site packs its files and database in steps, the copies are verified, and the backup appears as restorable — before you rely on the schedule. ## When something is not green [#when-something-is-not-green] Every status in the dashboard names its cause rather than a generic failure. The [Troubleshooting](/application/troubleshooting) section is organised by what you see: a site the platform cannot reach, a worker error, a permission refused, an update that failed, a backup that did not finish, a queue that is slow. --- # Getting started URL: https://wpocto.com/docs/application/getting-started From a new workspace to a connected, checked site, in six short steps. Six pages, in the order you will need them. The whole road from an empty workspace to a site that reports in and has been checked takes a few minutes per site once the first one is done. --- # Install and connect the worker URL: https://wpocto.com/docs/application/getting-started/install-the-worker Put the WP Octo worker plugin on the site and pair it with the platform. The worker is an ordinary WordPress plugin. It is installed like any other plugin and paired with the platform through one credential, the **workspace token**. ### Install the plugin [#install-the-plugin] Upload the WP Octo plugin zip through **Plugins → Add New → Upload Plugin** in the site's WordPress admin, and activate it. The plugin adds an **Octo Tools** menu. The zip is the current release of the worker, offered from the dashboard: open the site under **Websites**, choose **Connect Website**, and use **Download Plugin**. From then on the worker keeps itself up to date: the platform tells it when a release is available for its site, and the worker installs it with a rollback copy kept outside the plugin folder. ### Pair it with the workspace [#pair-it-with-the-workspace] The site has to hold the workspace token, and there are two ways it gets there: * **The platform installs it.** When the site was added to the dashboard first and the platform can reach it, WP Octo places the token on the site itself. Nothing to do on the site. * **Paste it.** Open **Octo Tools → Settings → General** on the site and paste the workspace token from the WP Octo dashboard. Use this when the site is being set up on its own, or when the host's firewall keeps the platform from reaching the site. The site accepts one credential, and it is this one. It is checked on every call and never written into a backup. ### Check the connection [#check-the-connection] Back in the dashboard, open the site's **Health** page and run a health check. A connected site answers with its worker version and starts appearing with a status of *active*. If the platform cannot reach the site, the page names the cause — a DNS problem, a certificate, a firewall answering instead of the site, a plugin that took the credential before the worker saw it — and what to do about it. [Connection problems](/application/troubleshooting/connection-problems) has the list. ## What the worker does on the site [#what-the-worker-does-on-the-site] From this point the platform and the site talk in both directions: * **The platform calls the site** to read its inventory, run an update, take a backup, restore one, or update the worker itself. Every call carries the workspace credential. * **The site calls the platform** on its own schedule — every fifteen minutes by default, sooner when there is work — to report its state and pick up instructions. This is the channel that keeps working when a host firewall blocks the platform's calls, and it is why a blocked site still shows current data. The [Worker plugin](/worker) section describes the plugin in full: what it needs from the host, how it connects, how it updates itself, and how it recovers when something goes wrong. --- # Common next steps URL: https://wpocto.com/docs/application/getting-started/next-steps Where to go once the first site is connected and checked. * **Add the rest of the fleet.** Repeat [Add your first website](/application/getting-started/add-your-first-website) per site, or add the sites first and install the worker on each afterwards. A site that was added but not yet connected simply waits. * **Set the update rhythm.** Packages carry the update frequency; each site chooses its update weekdays. Scheduled rounds run on that rhythm with a backup first and a rollback when the checks fail — [Updates](/application/updates). * **Decide where backups live.** A package's storage policy says whether a backup stays on the site, goes to object storage, or both. External storage is configured per workspace; see [Backups](/application/backups). * **Invite the team, and the customers.** Members with the *user* role work on the sites; *client* members see only their own — [Roles and permissions](/application/roles-and-permissions). * **Watch the fleet from the dashboard.** The home screen summarises health across all sites and shows what happened recently — [Dashboard](/application/dashboard). * **Integrate.** An API key from workspace settings lets an integration read the workspace's sites — [API](/api). --- # Requirements URL: https://wpocto.com/docs/application/getting-started/requirements What a site needs before WP Octo can look after it, and what WP Octo itself runs on. ## The WordPress site [#the-wordpress-site] The worker plugin is written to run on ordinary hosting, shared hosting included. It needs: | | Requirement | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | PHP | 7.4 or later. The plugin is checked against every version from 7.4 to 8.5. | | WordPress | 5.2 is the declared minimum; 5.9 and later are the versions the plugin is actually booted against. Between the two it should work and has not been checked. | | Web server | Anything that runs WordPress. Apache and LiteSpeed with `.htaccess`, or nginx. | | PHP limits | The worker is designed to work with 30 seconds of execution time and 128 MB of memory. It does its work in short steps that survive a timeout; more headroom makes it faster, not more correct. | | Outbound HTTPS | The site must be able to reach `wpocto.com` over HTTPS. This is what every managed site uses to report in, and it is the one connection that keeps working on hosts whose firewall blocks incoming calls from the platform. | | WP-Cron | The site's own scheduler. Many things the worker does between calls from the platform — continuing a backup, syncing its state — run on WP-Cron, so a site where WP-Cron is disabled and no system cron replaces it does that work only when the platform calls or a visitor arrives. | WP-CLI, shell access and a database console are **not** required. The worker never assumes them. Hosts that run bot protection (Imunify360, Sucuri, Cloudflare, Wordfence) sometimes refuse the platform's calls to the site. Since worker 2.3.0 the site keeps its data current and takes its work over its own outbound calls in that situation. The [hosting compatibility](/worker/hosting-compatibility) page explains what still needs a person. ## The site's address [#the-sites-address] A site is identified by the address WordPress reports as its home. That address must answer directly: a site that redirects to another address — `http://` to `https://`, without to with `www` — is refused when it is added, because a redirect strips the credential from the platform's calls and turns a write into a read. Enter the address the site actually answers on, including the path when WordPress lives in a subdirectory. ## The workspace [#the-workspace] A workspace is created with an account on [wpocto.com](https://wpocto.com). The person who creates it is its administrator; further members join by invitation. Plans and subscriptions, where they apply, are managed under workspace settings. ## Browsers [#browsers] The dashboard is built with current web technology and is used in a current version of Chrome, Firefox, Safari or Edge. It works in light and dark mode and on a phone. --- # Account and workspace URL: https://wpocto.com/docs/application/getting-started/workspace Your account, the workspace your sites live in, and who else can be in it. ## One account, one or more workspaces [#one-account-one-or-more-workspaces] You sign in to WP Octo with an email address and a password, or with one of the sign-in providers offered on the login page. Two-factor authentication can be enabled from your profile. Everything you manage lives in a **workspace**. An agency typically has one workspace for all the sites it looks after; a hosting company may have several. Sites, backups, update rounds, clients, packages and API keys all belong to the workspace, and nothing in one workspace is visible from another — that separation is a property of the product, not a setting. ## Members and roles [#members-and-roles] A workspace has members, and every member has one role in it: | Role | What it is for | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Administrator** | Everything: sites, updates, backups and restores, clients, packages, team, settings and API keys. The person who created the workspace starts as its administrator. | | **User** | Sees every site and its pages, and can log in to a site's admin through the dashboard. Changes nothing on the platform itself: rounds, backups, restores and site settings are an administrator's. | | **Client** | Read-only. A client is attached to one or more client accounts and sees only the sites that belong to them: their status, their update rounds, their backups. A client cannot start an update, a restore, a backup, or log in to a site through the dashboard. | Members are invited from **Team** in the dashboard, with the role they should have. What each role may do is spelled out under [Roles and permissions](/application/roles-and-permissions). ## Clients [#clients] A **client** is the customer whose site it is: a company or a person your agency works for. Every site is attached to a client, and clients can be given their own read-only members. Clients also carry the notification preference for the emails WP Octo sends about a site's updates. ## Packages [#packages] A **package** is the service level a site is on: how often it is updated, how often and where it is backed up, how many pages of it are monitored and how often. You define packages once and assign one to every site; a site can override a package's backup settings on its own. See [Packages](/application/packages). ## Workspace settings [#workspace-settings] Under **Workspace settings** an administrator finds the workspace's name and details, its billing where that applies, and its **API keys** — the credential an integration uses to read the workspace's data through the [API](/api). Keep API keys out of managed sites: a site holds a credential of its own, and an API key on a site would hand the platform to whoever compromises that site. --- # Authentication issues URL: https://wpocto.com/docs/application/troubleshooting/authentication-issues Signing in, two-factor, API keys, and tokens on sites. ## Cannot sign in [#cannot-sign-in] The password reset is on the login page. If the login page itself shows an error before you have entered anything, that is a platform problem; report it. ## Two-factor [#two-factor] Recovery codes are shown when two-factor is enabled and can be regenerated from the profile. Without the device and without a code, write to support. ## An API key is refused [#an-api-key-is-refused] A revoked key stops working at once; check the key under workspace settings. The key goes in the `Authorization` header as a bearer token — [Authentication](/api/authentication). ## A site refuses the token [#a-site-refuses-the-token] The site holds a token that is not the workspace's, or another plugin answered before the worker — [Connection problems](/application/troubleshooting/connection-problems). Paste the current workspace token into **Octo Tools → Settings → General** on the site. ## The magic login does not work [#the-magic-login-does-not-work] The site issues a ticket valid once and for one minute; a ticket used twice or too late is refused, and a new one is issued by clicking again. A site that redirects, or one behind a firewall that challenges the request, refuses the platform's call for the ticket — the Health page shows which. --- # Backup and restore issues URL: https://wpocto.com/docs/application/troubleshooting/backup-and-restore-issues A backup that stopped, a copy that is missing, a restore that was refused. ## A backup is taking long [#a-backup-is-taking-long] A backup is a sequence of small steps and the platform continues it where it stopped; a slow backup is not a failed one. The platform decides failure only from the site's own reported progress — no change for a set time, or a backup older than its ceiling. Leave it; check the site's Backups page for its step and percentage. ## A backup failed [#a-backup-failed] The row says why. The reasons that recur: * **Worker inactive** — the scheduled slot came and the platform could not reach the site. One retry follows an hour later; the site's connection is the thing to fix. * **External storage unavailable** — the policy needs object storage the workspace has not configured or that refused the credential. Configure it under workspace settings; a policy that needs external storage is never quietly downgraded to keeping the copy on the site. * **Stalled** / **timeout** — the site stopped reporting progress. Usually the host killing requests; see [Hosting limitations](/application/troubleshooting/hosting-limitations). **Resume** tries again from the last step. * **Verification failed** with a chunk named — a chunk in storage does not match what the site computed. The backup is not a restore point; take another. ## A copy is "missing" or "unreachable" [#a-copy-is-missing-or-unreachable] Every backup shows the state of each copy. **Unreachable** means the site or the storage could not be asked; the copy still counts and is asked again next hour. **Missing** means the site or the storage answered that it is not there. A backup with no available copy is not offered for restore. **Check copies** reconciles now. The platform never deletes an artifact while reconciling; if a copy is missing, something else removed it. ## A restore was refused [#a-restore-was-refused] * **Backup not local** — the site's copy is not wholly on disk; the platform fetches the external copy instead when there is a whole one, and says so if there is not. * **Worker does not support fetch** — restoring from external storage needs worker 2.2.0 or later on the site. * **Another operation is running** — wait for it; the restore is queued behind the site's lock. ## A restore completed but the site looks wrong [#a-restore-completed-but-the-site-looks-wrong] A restore from a backup made before a change puts the site back before that change, including plugins and settings — except, from worker 2.3.0, the site's connection to the platform and the work in flight. Check which backup was restored from and its date. --- # Connection problems URL: https://wpocto.com/docs/application/troubleshooting/connection-problems The platform cannot reach a site, or what it holds about a site is out of date. ## "The platform cannot reach this site" [#the-platform-cannot-reach-this-site] Open the site's **Health** page. The connection section shows the cause the last probe found and, for the causes where a person is needed, what to change. The full list with the meaning of each is in the worker section, [Troubleshooting the worker](/worker/troubleshooting). The ones seen most: * **Blocked by a firewall** — the host's bot protection answered instead of the site. Allow the platform's address as the instruction on the page says. Since worker 2.3.0 the site keeps reporting and taking its work on its own meanwhile, so an unreachable site is not a neglected one. [Hosting compatibility](/worker/hosting-compatibility). * **Authentication failed** — the site refused the workspace token. If the page says a JWT plugin is involved, exclude the worker's namespace in that plugin or bring the site to 2.3.0. Otherwise the token on the site is not the workspace's: paste the current one into the worker's settings. * **Plugin inactive** — activate the worker on the site, or reinstall it. * **SSL error**, **DNS error** — fix on the host or at the registrar; the platform notices on its next probe. * **Timeout** — the host is slow; the platform asks again on a widening schedule. You never need to tell the platform that a cause was fixed. It asks again — after minutes for a temporary cause, after hours for a structural one — and marks the site recovered on the first reachable answer. **Run health check** asks now. ## The site was added but never connected [#the-site-was-added-but-never-connected] The worker is installed and paired in two steps — [Install the worker](/application/getting-started/install-the-worker). If the plugin is active and the site still shows as never reporting, run a health check and read the cause. ## A site's data is old [#a-sites-data-is-old] Each page of a site shows when its dataset was last received and over which channel. Two situations: * **The site is reachable, and one dataset is stale.** The platform's own read of that dataset failed — a timeout, an error on the site — and the failure was recorded rather than a fresher time invented. **Sync** on the page reads it again. * **The site is not reachable inbound, and everything is ageing.** The site's own outbound calls have stopped. On a site with a firewall that is the channel that keeps data current, and it runs on the site's WP-Cron: a site with WP-Cron disabled and no system cron in its place does not call. Load a page on the site, or ask the host about cron. ## The site redirects [#the-site-redirects] A site whose address redirects — to `https`, to `www`, to another path — is refused when it is added, and one that starts redirecting later shows as unreachable with the redirect as the cause. Edit the site's address to the one it actually answers on. The platform never follows a redirect on an authenticated call, because a redirect would strip the credential. --- # Hosting limitations URL: https://wpocto.com/docs/application/troubleshooting/hosting-limitations What a host can do to get in the way, and what to change. | Symptom | Likely cause | What to change | | -------------------------------------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | | Health page says **blocked by a firewall** | Imunify360, Sucuri, Cloudflare or Wordfence treats the platform as a bot | Allow the platform's address where the page says; expect the site to keep reporting outbound meanwhile | | **Authentication failed**, JWT named | a JWT plugin answers bearer tokens before the worker | Exclude the worker's `wpocto/v1` namespace in the plugin, as the Health page says, or bring the site to worker 2.3.0 | | **Authentication failed** on a CGI/FastCGI host, token correct | the host strips the `Authorization` header | Worker 2.3.0 reads the platform's own header; on older workers, the host's rewrite rule for `Authorization` | | Data does not change after a sync | a page cache stores the REST API | Exclude `wp-json/wpocto/v1` in the cache plugin; LiteSpeed Cache is told directly by the worker | | Backups never get past a step | the host kills requests before a step finishes | Ask for the standard thirty seconds; the worker adapts step size but cannot work in a few seconds | | Outbound data ages while the site is up | WP-Cron disabled with no system cron | Enable WP-Cron or add a system cron calling `wp-cron.php` | | The site cannot call the platform at all | outbound HTTPS blocked by the host | Allow `wpocto.com` outbound | | Timeouts on everything | an overloaded host | The platform backs off; the host needs attention | The worker is designed for thirty seconds and 128 MB, no shell and no WP-CLI. A host that gives less than that is outside what it is built for. [Requirements and hosting](/worker/requirements-and-hosting). --- # Troubleshooting URL: https://wpocto.com/docs/application/troubleshooting Start from what the dashboard shows you; every status names its cause. WP Octo is built so that a failure names its cause rather than a generic state. So the first step is always the same: read the reason the dashboard gives — on the site's Health page, on the update round, on the backup — and then find it here. If none of these fits, write to [support@wpocto.com](mailto:support@wpocto.com) with the site, the page you were on, and the reason the dashboard showed. --- # Something has not started URL: https://wpocto.com/docs/application/troubleshooting/operations-not-starting An update round, a backup, a restore or a health check you started has not begun. Every operation on a site runs one at a time, and some of them wait for the site itself. A delay has one of three causes: * **Another operation on the same site.** A backup started while an update round runs waits for the round. The site's Health page lists the work waiting for it. * **The site is unreachable from the platform's side.** Work the platform cannot push is handed to the site over the site's own calls, which it makes every fifteen minutes on its WP-Cron — so a backup on a firewalled site begins on the site's next call, not at once. [Connection problems](/application/troubleshooting/connection-problems). * **The platform is busy.** Operations start in order; a brief pause on the platform's side delays a start by a minute or two. An operation the platform's own work was interrupted on ends as such and is run again. An operation that has not begun after an hour with none of these applying is worth reporting, with the site and the time. --- # Permissions URL: https://wpocto.com/docs/application/troubleshooting/permissions Something is refused, or a page is not in the navigation. ## "You do not have permission" [#you-do-not-have-permission] What a member may do is decided by their role — [Roles and permissions](/application/roles-and-permissions). A **client** is read-only by construction; a **user** works on sites but does not manage the workspace; an **administrator** does everything. Ask an administrator to change the role, or to do the action. ## A page is missing from the navigation [#a-page-is-missing-from-the-navigation] Pages are shown only to roles that may use them. Team, workspace settings and billing are administrators' pages. A client sees only sites, and only the sites of the clients they are attached to — a client attached to no client account sees nothing. ## An invitation was not received [#an-invitation-was-not-received] Invitations are sent by email to the address entered; check the address on the Team page and the recipient's spam folder. An invitation is accepted by signing in or registering with that address. ## The API returns 401 or 403 [#the-api-returns-401-or-403] `401` is no key or an invalid one; `403` is a valid key that may not do this. Keys are created and revoked under workspace settings by an administrator — [Authentication](/api/authentication). ## The site refuses the platform [#the-site-refuses-the-platform] That is a site-side credential, not a dashboard permission: see [Connection problems](/application/troubleshooting/connection-problems). --- # Update failures URL: https://wpocto.com/docs/application/troubleshooting/update-failures A round rolled back, a plugin was refused, or verification failed. ## The round rolled back [#the-round-rolled-back] A round rolls back when its checks fail after the updates: the front page or the admin did not answer, or a regression page changed beyond its threshold. The round's record says which check and what it found. The site is back on the versions it had before the round; nothing further is needed for the site. What to do about the update itself depends on the cause — a page that changed because of a legitimate redesign in a theme update needs its threshold reconsidered or a new baseline; a plugin that breaks the site needs the plugin's author. ## A plugin was refused [#a-plugin-was-refused] Each plugin update in a round records the worker's own reason. The ones that recur: | Reason | Meaning | Retried? | | ------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | **licence required**, **empty package url** | a premium plugin whose licence is missing or expired on the site | no — the same refusal would come back, and the customer would be told three times | | **custom updater issue** | the plugin updates through a mechanism WordPress's updater cannot drive | no | | **download failed** | the package could not be fetched at that moment | yes, up to three attempts | | anything else | an unrecognised refusal | yes — declining a retry that would have worked costs the update; making a pointless one costs a request | A refusal that is not retried is recorded as *not retryable*, separately from *gave up*: one attempt was spent and the cause named, against three attempts exhausted. ## "Verification failed" [#verification-failed] The worker said it updated the plugin and the site does not show the new version. The platform records that as a verification failure, never as a success. Usual causes: a page cache answering for the site, or a plugin whose reported version does not change on update. Sync the plugin list and compare. ## The round ended unexpectedly [#the-round-ended-unexpectedly] The round stopped without writing an outcome: the platform's work on it was interrupted. The site is taken out of maintenance mode by the worker's own deadline if the platform did not manage it. Check the site, then run the round again. ## The round would not start [#the-round-would-not-start] The dashboard says why: the worker is older than the version that brings a site back on its own, the site is unreachable, or another operation holds the site. The first is fixed by the worker's rollout reaching the site; the platform asks the site for its version rather than reading what it last reported. [Compatibility](/worker/versions). ## A scheduled round did not run [#a-scheduled-round-did-not-run] Rounds run on the package's frequency on the site's update weekdays, checked hourly. A site whose worker is too old, or that is unreachable, is skipped and the reason recorded. --- # Worker errors URL: https://wpocto.com/docs/application/troubleshooting/worker-errors A PHP error on the site, a worker that will not load, a lock that is held. ## "Worker error" [#worker-error] The platform reached the site and got a PHP error back. The Health page shows what the site said. If the error is in another plugin or the theme, fix it on the site as you would any fatal error. If it is in the worker itself, the worker's own rollback puts the previous version back without loading the plugin — the platform does that itself when it detects a failed worker update — and on a site the platform cannot reach, uploading the current zip over the install is the manual equivalent. [Recovery](/worker/recovery). ## The worker will not load [#the-worker-will-not-load] If the plugin's files are incomplete, the worker stays out of the way rather than breaking the site on every request. The site works without it; the platform reports it as unreachable with the cause. Reinstall the current release. ## "Another operation is running" [#another-operation-is-running] The site is busy with a backup, a restore or a worker update. The platform waits and asks again; nothing is needed from you. A lock left behind by a crashed process expires after fifteen minutes on the site, and the platform releases its own hold on a site when the operation ends. A site that stays busy for longer than half an hour with nothing running is a defect; report it with the site and the time. ## A page cache answers for the site [#a-page-cache-answers-for-the-site] If a site's data does not change when it should — a plugin updated on the site, the list still showing the old version after a sync — a page cache in front of the site may be answering. The worker marks every answer to the platform as not cacheable, so this is rare; where it happens, exclude the `wp-json/wpocto/v1` path in the cache's settings — the same path the site's Health page names when the platform finds a cache answering for the worker. ## Where to look on the site [#where-to-look-on-the-site] **Octo Tools → Error log** and **Activity log**, and the worker's debug log under `wp-content/uploads/wpocto-log/`. --- # Accounts and access URL: https://wpocto.com/docs/application/security/accounts-and-access Three kinds of caller — a person, an integration, a site — and how each is identified. ## A person [#a-person] Signs in to [wpocto.com](https://wpocto.com) with an email address and a password, or through a sign-in provider offered on the login page. Two-factor authentication with a time-based code and recovery codes can be enabled from the profile. The login, registration and password-reset forms carry a captcha. What a signed-in person may do is decided by their **role in the workspace** — administrator, user or client. A client role is read-only and sees only the sites of the client accounts it is attached to. [Roles and permissions](/application/roles-and-permissions) lists what each role holds. ## An integration [#an-integration] Calls the [API](/api) with a **workspace API key** as a bearer token. The key is created and revoked by a workspace administrator under workspace settings, is shown once, and identifies the workspace, not a person. Everything an API call can read is scoped to that workspace. ## A site [#a-site] A managed site holds the **workspace token**, and the platform presents it on every call to the site; the site checks it and refuses anything else. When the site calls the platform, it identifies itself the same way, and the platform accepts it only as the site it is registered as in the workspace the token belongs to. Since worker 2.3.0 the site also holds a credential of its own for the calls it makes, issued by the platform, and the instructions it accepts from the platform are signed and valid once. [Connection](/worker/connection) describes the two directions. --- # Credentials URL: https://wpocto.com/docs/application/security/credentials The two credentials WP Octo has, where each belongs, and how each is kept. ## Two credentials that look alike and are not [#two-credentials-that-look-alike-and-are-not] | | What it opens | Belongs | | ------------------- | -------------------------------- | ----------------- | | **API key** | the platform's own API | in an integration | | **Workspace token** | the worker on every managed site | on the sites | Putting an API key on a managed site hands a key to the platform to anyone who compromises that site. Putting a workspace token in an integration gives that integration every site in the workspace. The dashboard shows each where it belongs, and the worker has nowhere to put an API key. ## How they are kept on the platform [#how-they-are-kept-on-the-platform] Secrets — workspace tokens, API keys, storage credentials — are stored encrypted. They are never shown in a page, written to a log, included in an export or put in an audit record. Where a person needs to recognise one, a fingerprint is shown. The worker plugin contains no storage credential and no platform credential. The zip you install is the same for every site; the pairing happens afterwards. ## How the workspace token reaches a site [#how-the-workspace-token-reaches-a-site] The platform installs it on the site where it can reach the site, and checks that the site accepts it — and refuses a wrong one — before it trusts the site. Where the platform cannot reach the site, an administrator pastes the token into the worker's settings — [Install and connect the worker](/application/getting-started/install-the-worker). ## Revoking [#revoking] An API key is revoked under **Workspace settings → API keys** and stops working at once; create a new one for the integration. For the workspace token, contact support. ## Object storage [#object-storage] The site never sees a storage key. To upload a backup or download one for a restore, the platform hands the site links that read or write one file for a limited time. --- # Data handling URL: https://wpocto.com/docs/application/security/data-handling What the platform stores about a site and a workspace, what it keeps from a site's contents, and for how long. ## About a workspace [#about-a-workspace] Accounts, members, roles, invitations, clients and their contacts, packages, API keys (encrypted), subscriptions and orders where billing applies, and the workspace's storage configuration (credentials encrypted). ## About a site [#about-a-site] * Its address, name, client, package and settings. * The **inventory** it reported: plugins, themes, users, core version, health, environment — kept current over both channels, with the age of each dataset recorded. * **Update rounds**: what was updated, what was backed up first, what the checks found, what was rolled back, with the site's own reasons where an update was refused. * **Backups**: the list of pieces of each, where each copy is and whether it was verified, and — for a storage policy that keeps an external copy — the backup itself in the workspace's object storage. * **Monitoring**: the checks and their log for ninety days. * **Reports**: Lighthouse results and thumbnails, where enabled. * **Health**: what the platform found each time it could not reach the site, and when the site last called in. * **Notes** a member wrote about the site. ## What the platform does not keep [#what-the-platform-does-not-keep] * The site's **content**, other than inside a backup the workspace asked for. * Any **storage credential** on the site. * **Secrets in logs or audit records**. A secret that must reach a person is shown as a fingerprint. ## Retention [#retention] Monitor logs are removed after ninety days. Backups are kept according to the workspace's storage policy and the retention the package sets; the platform never deletes a backup on a site or in storage as a side effect of checking its records — a leftover is a finding for a separate decision. Those checks run hourly and after every backup, restore and delete, and correct the platform's records to what the site and the storage actually hold, never the reverse. ## Where it runs [#where-it-runs] The platform runs in the European Union. Backups go to the object-storage bucket the workspace configures, in the region that bucket is in. --- # Security overview URL: https://wpocto.com/docs/application/security WP Octo holds the keys to other people's WordPress installs. This section says how those keys are kept, and what is not checked. WP Octo is a control plane for sites that belong to its customers' customers. Every design decision in this section follows from that: a mistake here is not a bug in a dashboard, it is a stranger inside someone's site. ## The short version [#the-short-version] * **One workspace never sees another.** Tenant isolation is a property of the product, not a setting — [Tenant isolation](/application/security/tenant-isolation). * **Two credentials, kept apart.** An API key opens the platform's API; a workspace token opens the worker on a site. Neither belongs where the other does — [Credentials](/application/security/credentials). * **A site trusts one thing** — its workspace token — and refuses everything else — [What the plugin stores and trusts](/worker/security). * **The platform trusts nothing it did not verify.** A firewall's page is not the site; an update the site reports as done is checked on the site before it is called done; a site is only trusted with a credential after it has refused a wrong one. * **Secrets are encrypted at rest and never shown, logged or exported.** Where a person needs to recognise one, they see a fingerprint. * **A site never holds a storage credential.** Backups reach object storage through links the platform hands the site for one file and a limited time. * **One operation at a time on a site.** A backup, a restore, an update round and a worker update never run on the same site at once, so a restore cannot overwrite what a backup is reading. ## What is not checked [#what-is-not-checked] Where WP Octo has no check for a class of problem, the documentation says so rather than implying one: * **A publicly readable log or debug file on a managed site.** WP Octo does not look for this, and the site's Security page in the dashboard is a placeholder — [Pages not yet available](/application/pages-not-yet-available). * **The contents of a site's plugins and themes** for vulnerabilities. The platform reports versions and available updates; it does not scan code. * **Threats and firewalls.** The dashboard's security card shows the one signal the platform collects across the fleet, the state of every site's TLS certificate, and nothing more. ## What this section does not do [#what-this-section-does-not-do] It does not describe the platform's own infrastructure. Those are operational details and are kept out of public documentation on purpose. --- # Reporting a vulnerability URL: https://wpocto.com/docs/application/security/reporting How to tell us about a security problem in the platform or the worker, privately. If you believe you have found a security problem in WP Octo — the platform, the worker plugin, or the way the two talk — please tell us privately rather than in a public issue. **Email:** [support@wpocto.com](mailto:support@wpocto.com), with *Security* in the subject. Include what you found, how to reproduce it, and which site or workspace it concerns if it is specific to one. If your report involves a customer's site, do not include that site's data; a description of the shape of the problem is enough. ## What we ask [#what-we-ask] * Give us reasonable time to fix a problem before you describe it publicly. * Do not access, change or delete data that is not yours while investigating. Reproduce against a site or workspace you control. * Do not run scans or probes against managed sites; they belong to customers, and a firewall on their host will read it as an attack. ## What we do [#what-we-do] We acknowledge the report, tell you what we found, fix what needs fixing, and tell you when it is out. Fixes to the worker reach sites through the normal staged rollout; fixes to the platform go out with the next update. The two changelogs — [application](/application/changelog) and [worker plugin](/worker/changelog) — record what shipped. --- # Tenant isolation URL: https://wpocto.com/docs/application/security/tenant-isolation A workspace never sees another workspace's data. That is the product, not a quality bar. Every site, backup, update round, client, package, monitor, API key and member belongs to exactly one workspace, and everything the dashboard and the API show is scoped to the workspace of the caller. That is not something a screen opts into: it is how every screen and every endpoint is built, and a change to the platform is not accepted until it has been shown to hold. ## What this means in practice [#what-this-means-in-practice] * A member of workspace A cannot open, list, search or act on anything in workspace B, whatever address they type. * An API key of workspace A returns only workspace A's sites. * A site's own calls to the platform are accepted only as the site registered in the workspace whose token the site presented, and as nothing else. * Selecting many sites in a list gives nobody more than they have on one site. A member allowed to view sites but not to act on them cannot act on all of them at once through a checkbox. ## What a client member sees [#what-a-client-member-sees] A member with the *client* role sees only the sites of the client accounts they are attached to, read-only: status, update rounds, backups, plugins, themes, core, health, reports, notes and monitoring. They cannot start anything, restore anything, or log in to a site through the dashboard. --- # List the websites of the caller's workspace URL: https://wpocto.com/docs/api/reference/websites/get-dashboard-websites {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}