You sent three caption options on Tuesday. The client replied “looks good” on Thursday. You published Friday. Three weeks later they say that was not the caption they signed off on. The approval sits in the thread, two words under four images and two rewrites.
The “looks good” that turns into a dispute
The shape is almost always the same. Approvals run through whatever channel the client already answers in, a text thread or an email reply, and drafts go up that thread across days. Sometimes there is no draft at all, just a description of one.
The ambiguity is not in their intent. They probably did mean yes. It is that the reply carries no reference to what it approves: not a draft, not a revision, not a file, not a date. If two versions went out that week, or a photo was swapped after the first round of feedback, “looks good” fits either one. The timestamp does not close the gap. It records when a message was sent, not what was on the client’s screen. This is not an edge case. It is the exact failure that timestamped, version-bound approval records exist to close off.
The two things a formal approval tool actually keeps
The clearest documentation of this pattern comes from developer review tools, which publish their data structures. The mechanics are the point, not the products.
- A timestamped record attributed to an account. GitHub’s REST documentation for pull request reviews shows a review as its own object: a state of APPROVED, a submitted_at value carrying a full date and time, and a user block identifying who submitted it. It is a discrete event, not a line of chat near one. Frame.io’s save counter likewise carries the date, time and author of each save.
- A reference bound to one exact version. That same review object carries a commit_id, pinning the approval to one state of the work. GitHub’s branch protection documentation describes an optional setting on top of that: GitHub records the state of the diff at the point of approval, and with the setting enabled, a change to that diff dismisses the approving review as stale until the work is approved again. GitLab has a setting named “Remove all approvals when commits are added to the source branch.”
- A sign-off action separate from talking. GitHub’s reference page for pull request reviews lists the decisions a reviewer picks between: a comment review leaves general feedback without explicitly approving or requesting changes, and approve is its own decision. A text thread has no button, only language, and “fine, go” lands in the same stream as everything else.
Why a text thread doesn’t create either one
Quoting a specific message helps but does not solve it. Send a carousel as six separate images, have the client quote the first one with “approved,” and you have a reference to an image, not to the set and not to the caption.
The deeper problem is that the record is mutable. Slack’s help documentation states that members can edit and delete messages they have sent, that owners and admins can delete members’ messages too, and that deleting a message is permanent. Telegram’s FAQ describes deleting individual messages or entire chats for both parties. The thread you treat as evidence is one either side can alter afterwards.
Email is a slower version of the same hole. A thread with drafts attached across five replies ends with “yes, approved” under a quoted chain containing draft_v1.png, draft_v2.png and a revised copy doc. Threading is a display convention, not a binding between an approval and an attachment.
What to do before you rely on a text approval
You can rebuild most of what a tool keeps in the same channel, without buying anything, if it happens before the approval.
- Put the exact draft in the same message as the ask. Not up the thread, not “as discussed yesterday.” Attach the screenshot, file or link and write the ask beneath it: “Approving this exact image and this exact caption for Friday 11 September.” The reply then sits adjacent to one artifact, and any revision goes out as a new ask with its own attachment.
- Ask them to name the thing in their reply. A bare “looks good” is the fastest thing to type, so give them something faster to repeat. “Reply with ‘approved, Friday carousel v2’ and I’ll schedule it” gets you a reply carrying its own reference. A file name or the caption’s first few words work as well. You want a client-typed string that could only describe one draft.
- Store the approval next to the file it approved. Screenshot it into a dated folder with the asset that went out, named so the pairing is obvious: 2026-09-11-friday-carousel-v2, holding the final image, the caption as text, and that screenshot.
When a text approval stops being enough
| Situation | What a dispute costs | What is enough |
|---|---|---|
| One-off post, small client, no claims in the copy | An awkward conversation, maybe a free repost | The text approval, with the draft attached to that same message |
| Recurring retainer, several posts a week | Six months of approvals cannot be reconstructed from a scrollback, so one disputed post puts every earlier one in question | A named reference in every approval reply, plus a dated folder pairing each approval with its asset |
| Content carrying a price, promotion, discount code or product claim | The client may have to honour or retract something publicly, and someone will ask who approved it | A version-referenced approval in writing before publishing, kept with the exact asset |
The trigger for moving to a formal approval workflow tool is not a post count. It is the point where answering “what did they actually approve” means scrolling back and guessing, and guessing wrong costs you the retainer or the invoice.
The first time a client disputes what they approved
Pull the whole thread, not just the approval message. What you want is the last message before it that contained an actual draft: an image, a file, a pasted caption. If there is exactly one such message and nothing was sent between it and the reply, you have reconstructed the version reference after the fact. Lay both out with their send times.
Sometimes it is not there. If two drafts went up that morning, or a file was replaced, or the only thing preceding the approval was a description rather than the post itself, the thread does not tie the approval to one version and no careful reading will make it. That is worth saying rather than implying a workaround always saves it. What was approved is then not answerable from your records, and how it ends depends on the relationship.
The lesson is narrow. You did not lack an approval. You lacked the two records a formal tool writes automatically: the moment of sign-off tied to a person, and a pointer to the exact draft. Both can be produced by hand.
Related reading on this blog
Nearby: what UGC rights-management tools actually record, what counts as a signed document under a free e-signature plan, and sharing brand account access without sharing a password.
Sources verified 7 September 2026 by fetching each vendor’s own documentation. This is a general practice piece. It is not Watchdog data and not on the re-verification schedule, so treat the behaviour described here as accurate on the date checked and nothing further. followedapp is published by the team behind RecurPost, and RecurPost is covered vendor #34 under the same rules as every other vendor.
FAQ
Is a client’s text message legally binding as an approval?
That is a question for a lawyer in your jurisdiction, and this site cannot answer it. The operational problem arrives first regardless: a bare “looks good” usually does not specify which draft it approves, and that ambiguity is what turns a disagreement into a dispute however a court would treat the message.
Do I need to buy an approval workflow tool just to avoid this?
No. For a single freelancer or a small account load, pairing the exact draft with a client-typed reference in the same exchange closes most of the gap, and a dated folder holding the approval screenshot beside the final asset closes the rest. It stops scaling when volume or client count makes that discipline unreliable, or when content carries stakes such as a promotion or a product claim.
What should I do if I can’t tell which draft a client’s old approval message refers to?
Work back to the last message before the approval that carried an actual draft rather than a description. If exactly one draft sits there, that is your version reference. If two went up the same morning, or a file was replaced, it sometimes cannot be reconstructed, and the fix is closing the gap on the next approval.
Sources
- GitHub REST API, pull request reviews, on review objects carrying state, submitted_at, commit_id and user. Fetched 7 September 2026.
- GitHub, about protected branches, on optional dismissal of stale approvals. Fetched 7 September 2026.
- GitHub, pull request reviews reference, on comment as distinct from approve. Fetched 7 September 2026.
- GitLab, merge request approval settings. Fetched 7 September 2026.
- Frame.io, versioning, on the date, time and author recorded per save. Fetched 7 September 2026.
- Slack, edit or delete messages. Fetched 7 September 2026.
- Telegram FAQ, on deleting messages or chats for both parties. Fetched 7 September 2026.
