When pausing work is fair
Locking a client out is a consequence, so ask the same question you’d ask of any other: would a reasonable client see it coming? Three things make the answer yes.
- It’s in the agreement. They signed something that says unpaid invoices pause the work.
- They were told the date. The final notice names the day access pauses, a few days ahead, so they can pay first.
- It’s undone straight away. The moment they pay, everything comes back, without them having to ask.
And one rule on top: if they dispute the work, stop and talk to them first.
Put it in the contract
Add a clause like this to your next proposal or terms. It’s short on purpose. A rule a client can read in ten seconds is easier to agree to.
If an invoice is more than 14 days overdue, Your Agency Studio may suspend access to staging sites, client portals and undelivered work, after giving at least 3 days’ written notice of the date. Access is restored as soon as the invoice is paid in full. Suspension does not change the amount owed or the dates in this agreement.
A starting point, not legal advice. Have it checked for your country before you rely on it, especially if any of your clients are consumers rather than businesses.
What to lock, and what not to
Lock what you’re still providing, not what they already own.
- Good candidates: a staging or preview site, a client portal or dashboard you host, downloads of files not yet handed over, the next sprint or round of revisions.
- Think hard first: a live production site. Taking it down hurts their customers as well as them, and it’s much harder to defend as proportionate.
- Don’t: hold back work they’ve already paid for, or anything the contract says they own.
Doing it by hand
By hand, it takes four steps.
- On day 10, send the final notice with the date access pauses (our final notice template).
- On that date, check the invoice is still unpaid, then switch on maintenance mode, revoke the portal login or remove the download links.
- Send the “work is paused” email with the pay link.
- Watch for the payment, and restore everything the same day it lands.
Step 4 is where doing it by hand goes wrong. A client who paid on Friday evening and is still locked out on Monday has a real complaint.
Doing it with a webhook
This is the last step of UntilPaid’s ladder. When the date in the final notice passes and Stripe still shows the invoice unpaid, UntilPaid sends a signed request to an address you choose. When Stripe marks it paid, a second request unlocks it.
POST /your-endpoint{
"event": "invoice.access_revoke",
"stripeInvoiceId": "in_1Qk8aZ…",
"stripeCustomerId": "cus_R2x7…",
"amountDue": 480000,
"currency": "usd"
}
POST /your-endpoint{
"event": "invoice.access_restore",
"stripeInvoiceId": "in_1Qk8aZ…",
"stripeCustomerId": "cus_R2x7…",
"reason": "paid"
}
Both are trimmed, and the real requests carry a few more fields. Amounts are in cents, so 480000 is $4,800.00. Your endpoint does the actual locking, so it can be anything you control: a staging site’s password, a portal flag, a WordPress plugin.
Verifying it’s really us
Each request carries an x-untilpaid-signature-v1 header: t=<unix time>,v1=<signature>. The signature is an HMAC-SHA256 of the time, a dot and the raw body, keyed with your signing secret, in hex. Reject anything older than five minutes.
import crypto from "node:crypto";
export function verifyUntilPaid(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map(p => p.trim().split("=", 2)));
const t = parts.t || "", v1 = parts.v1 || "";
if (!/^\d+$/.test(t) || !/^[0-9a-f]{64}$/i.test(v1)) return false;
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(v1, "hex"), Buffer.from(expected, "hex"));
}
The dashboard has ready-to-use receivers for Node.js, Python and PHP, a WordPress plugin, and a button that sends a test lock and unlock to your endpoint.
The safeguards built in
- Per client, not account-wide. You switch Lock access on for each client, confirming their contract allows it.
- Never out of the blue. The final notice names the date, at least three days ahead.
- Disputes stop it. A disputed invoice pauses chasing until you’ve looked.
- Unlocks on its own. When the invoice is paid or voided, or you unlock it yourself, the unlock request goes out.
Lock access is on the Pro plan ($79 a month) and Agency. Starter sends the email ladder without it. The 14-day trial includes it.