054 —Business
Quoting legacy work: a four-tier scope letter that holds
The four-tier scope letter we send before touching anyone's legacy site. Quote the surface, ringfence the swamp, and keep the client honest about what they're actually asking for.
Last month a lead for legacy work came in from a Dutch agency that had inherited a 2014 WooCommerce store from a client whose previous developer had stopped answering email. The brief was four lines: "Make checkout work again. Add Mollie. Move off the shared host. Quote please, end of week." Attached was a ZIP of the live wp-content/ directory, 1.8 GB, with a plugins/ folder that contained 41 plugins, 9 of which were nulled, and a mu-plugins/ file called fix-checkout-final-v3.php dated 2019.
This is the moment where you either write a number on a napkin and learn to regret it, or you write a scope letter. We always write the scope letter. Quoting legacy work without it is the fastest way to turn a €4,000 job into a €17,000 apology, and the client into someone who tells other people you went over budget.
What follows is the structure of the letter we actually send. It has four tiers because legacy work has four kinds of unknowns, and pricing them as one lump is what gets you into the swamp.
Why a single number always loses
The pathology of legacy quoting is that the visible work and the invisible work look identical from the outside. "Add Mollie to checkout" is a four-hour job on a clean site and a three-week job on a site where the previous developer overrode woocommerce_payment_complete in a child theme that also redefines wp_mail(). You cannot tell which one you have until you are already inside.
A single fixed price forces you to either pad for the worst case (and lose the deal to someone who didn't) or quote the best case (and eat the difference). A pure hourly rate spooks the client, because they have been burned by hourly rates before and they are not wrong to be suspicious. The four-tier letter splits the difference: fixed where we can be honest about it, time-and-materials where we genuinely cannot, with explicit triggers between them.
Tier 1: the audit, fixed and cheap
The first tier is always a paid audit. Not free, not "we'll take a look," not a discovery call. A real invoice, usually between €450 and €900 depending on the surface area, payable before we touch the server. The deliverable is a written report, three to six pages, that tells the client what they actually have.
The audit covers, at minimum: PHP version and EOL status (php.net's supported versions page is the canonical reference), MySQL version, CMS core version and patch gap, list of plugins with last-updated dates, any nulled or abandoned plugins, server stack (Apache/nginx, mod_php or PHP-FPM), .htaccess oddities, custom code in mu-plugins or the active theme's functions.php, and any obvious security issues against the OWASP Top Ten.
The audit is fixed-price because we can scope it. We know how long it takes to look at a site (between two and six hours, almost always). The client gets a document they own, that they could in theory take to another developer. That last part matters: it lowers the perceived risk of saying yes, because they are not signing up to a project, they are buying a report.
About one in four audits ends there. The client reads it, decides the work is bigger than they thought, and either re-budgets or walks away. This is a feature, not a bug. We did not lose the project; we got paid to not take a bad project.
Tier 2: the ringfenced fix, fixed-price
Tier 2 is the work the audit proved is bounded. Concrete, scoped, testable. "Upgrade PHP from 7.2 to 8.2, including the three plugin patches identified in section 4 of the audit." "Replace the abandoned woocommerce-checkout-fields plugin with the equivalent in woocommerce-checkout-field-editor, migrating the seven existing custom fields."
The rule for what goes into Tier 2: we have read the code, we know the shape of the fix, and we can name the files we are going to touch. If we cannot name the files, it is not Tier 2.
This is where most of the actual money lives, and where the client feels like they are getting a real quote. The letter lists each item, the price, and the acceptance criteria. The acceptance criteria are the unglamorous part that saves you later. "PHP 8.2 upgrade is complete when: the site loads without fatal errors on staging, the checkout flow completes a test order end to end, and wp-cli core verify-checksums returns clean." If the client signs that, you cannot be told later that it also had to be faster.
Tier 3: the swamp, time-and-materials with a cap
Tier 3 is the swamp. It is the work we know exists but cannot price, because the unknowns are unknown. Classic Tier 3 items: "the email sending sometimes fails on Tuesdays," "the admin is slow," "there's a duplicate-order bug we can't reproduce."
We bill these hourly, in 30-minute increments, against a written cap. The cap is the most important word in the letter. "We estimate 6 to 10 hours. We will stop work at 12 hours and request a conversation before continuing." The cap protects the client from a runaway investigation, and it protects us from having to either eat the overage or have an awkward email at hour 14.
The wording we use, more or less verbatim:
Tier 3 items are billed at €95/hour in 30-minute units.
Our best estimate is shown per item. We will not exceed
150% of the estimate without written approval. If we hit
that ceiling, we stop, write up what we found, and you
decide whether to continue, pause, or close the item.Clients almost never object to this once they see it written down. The objection they have to hourly billing is loss of control. The cap gives them control back.
Tier 4: the deferred list
Tier 4 is everything the audit surfaced that the client did not ask about and that is not blocking. Outdated jQuery in the theme. A wp-config.php with DB_PASSWORD in plaintext and the file world-readable. An .htaccess with a 2017-era hotlink-protection block that is now also blocking the new CDN:
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?oldclient\.nl [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ - [F]We list these with a one-line description, a severity (info / should / must), and no price. The point of Tier 4 is not to upsell. It is to be on record that we saw the problem and named it. Six months later, when the CDN bill spikes or the database leaks, nobody can say we should have spotted it. We did, and here is the email.
About half of Tier 4 items get pulled into the next quarter's work. The other half sit there forever, which is also fine.
The cover note that does the actual selling
The four tiers are the body of the letter, but the cover note is what closes the deal. It is two paragraphs. The first says what we found in plain language: "Your site is on PHP 7.2, which stopped receiving security patches in November 2020. Three of your plugins have not been updated since 2018. Checkout currently fails for customers using iCloud Hide My Email because of a regex in your custom validation."
The second paragraph says what we recommend doing first, and why. Not all of it. The smallest bite that gets the client out of immediate danger. Usually Tier 1 plus one or two Tier 2 items. The rest can wait for the next quote.
What this looks like when we use Pier on the same job
When we built Pier we ran into this exact pattern from the other side. The audit phase is mostly reading: poking around wp-content/, opening wp-config.php, scrolling through .htaccess, running a few read-only queries against the database. The way we ended up handling it was to make the whole audit happen inside one app, with version history on every file we touch and a MySQL editor next to the file tree, so a four-hour audit stays four hours instead of becoming a yak-shave through three SFTP clients and Sequel Pro.
The smallest thing you could do today: take the next legacy quote request sitting in your inbox and, before replying with a number, write back with the price of the audit only. See what happens.
— Questions —
What if the client refuses to pay for a Tier 1 audit?
Then they are not a client for legacy work. The audit fee is the cheapest filter you have. Clients who refuse it are the same clients who will dispute the final invoice.
How long should the scope letter be?
Two to four pages. Cover note, the four tiers as a table, acceptance criteria for Tier 2, the Tier 3 cap clause, and the Tier 4 list. Anything longer stops being read.
Do you sign an NDA before the audit?
Yes, and we send our own one-page mutual NDA with the audit invoice. Using the client's NDA template usually adds two weeks of legal review for no benefit.
What about emergency work, where there's no time for an audit?
Same letter, compressed. Tier 1 becomes a 90-minute paid triage call. Tier 2 and 3 get quoted from that call. The structure still holds; only the clock changes.