- Documentation
- Client portal
- Quote and approve work requests
Quote and approve work requests
Scope a job, send the client a price, get their approval, log the hours you spend, and invoice it — without leaving the workspace.
Before you start
- The workspace must already have at least one client. If nobody holds the
workspace-clientrole, there is nobody to approve a quote and nobody to invoice. See Invite a client to a workspace. - To set a price or see costs you need to be an account owner or admin. Account members can do everything else — create requests, move work along, log hours, comment, attach files — but pricing and margin are closed to them.
- To send an invoice you also need Stripe Connect set up for the agency, and the
client_billingfeature on your plan.
A work request is one scoped job: a title, a description, an optional estimate, and a price. It carries its own conversation, its own attachments, and its own record of the hours you spent on it.
The lifecycle
A request moves through a fixed set of states, and each move belongs to one side:
| You see | The client sees | What it means | Who moves it |
|---|---|---|---|
| Draft | nothing | Being scoped. Not visible to the client at all. | Agency |
| Needs estimate | Submitted | Somebody asked for work and it has no quote yet. | Client (or agency) |
| Awaiting client | Awaiting your approval | You've sent a price. The ball is in their court. | Agency prices it |
| Approved / Declined | same | The client accepted or rejected the quote. | Client only |
| In progress → Delivered → Closed | same | The work itself. | Agency |
The two columns differ on purpose. The same state is named from each side's point of view, so a status never tells a customer to approve their own quote.
Two rules are worth committing to memory:
- Only the client can approve. There is no agency button that accepts a quote on their behalf, at any permission level. That is deliberate — an approval is the client's commercial consent.
- A draft is invisible. Nothing about a request reaches the client until it leaves
draft, including its attachments. Use drafts freely to scope work privately.
Step 1: Create the request
Open the queue
Switch into the client's workspace and go to Workspace → Work Requests, or visit
/[workspaceSlug]/workspace/work-requests.Add a request
Give it a title the client will recognise on an invoice and a description of what's in scope. Both are visible to the client once the request leaves draft, so write the description for them, not for your team.
Clients can also start one themselves from Work requests → New request in their portal. Theirs arrives as Submitted with just a title, description, and any files they attached — they can't set a price or an estimate.
Step 2: Price it
Open the request and fill in the estimate. Pick a basis:
- Fixed — you name a price, and that's what the client is billed.
- Hourly — you set a rate, and the bill is the rate times the hours you log.
- Retainer — the work is covered by an existing arrangement. Retainers are never turned into one-off invoices.
You also choose when it becomes billable: at approval, or on delivery. Delivery is the default and is the safer choice for anything open-ended — the request only becomes invoiceable once you've actually finished it.
Saving the estimate moves the request to Awaiting client and notifies them.
Account members don't see the price field, the margin panel, or the invoice button — the server omits that data from their response entirely, rather than hiding it in the interface. If a teammate reports the estimate form missing, check their account role.
Step 3: The client decides
The client sees the request in their portal at Work requests, with the description, the price, and the estimated hours. They can approve it, decline it with a reason, or ask a question in the comments first.
What they never see: your logged hours, your costs, your margin, or any comment you marked internal.
Step 4: Do the work and log hours
Move the request to In progress, then Delivered when it's done.
While it's open, log hours as you go from the request's detail page. Each entry takes a date, an hour count, and an optional note. Hours matter for two reasons: on an hourly request they're what the client is billed, and on every request they're what the margin panel measures your profit against.
The margin panel shows your logged hours, your effective hourly rate, and — when the request is linked to a workflow — what that workflow's AI runs actually cost. If no workflow is linked it says so rather than showing a zero, because "we didn't measure this" and "this was free" are different facts.
Step 5: Invoice it
Once the request passes its billable moment (approval or delivery, whichever you chose), an Invoicing card appears on the detail page. Click Generate invoice and the client is invoiced through your connected Stripe account, with the request's title as the line item.
The button is safe to click twice. Every invoice is keyed to the request itself, so a double-click, a lost connection, or a retry all land on the same invoice — you cannot accidentally bill a client twice for one job.
A retainer is a recurring arrangement, not a one-off charge, so no invoice button appears on one. Bill it through the client's subscription instead.
Comments: internal versus client-visible
Every request has one thread with two kinds of comment.
- Internal — your team only. This is the default for anything you write.
- Client-visible — shown in the client's portal, and they can reply.
Clients can only ever write client-visible comments; there is no way for them to author an internal note, and no way for them to read one. If you're discussing scope, cost, or whether to push back on a request, internal is where that belongs.
Ordering the queue
The queue is in manual priority order — drag a request to move it. The order is the agency's own; clients see their requests in their own view and never see your prioritisation.
Troubleshooting
The estimate form isn't there. Either you're an account member (pricing is owner/admin only), or the request has moved past the point where an estimate still applies. A priced, approved job isn't re-priced from this screen.
"This work request is not billable yet." It hasn't reached its billable moment. Check the invoice timing on the estimate — if it's set to delivery, mark the request delivered first.
The client says they can't see a request. Check it isn't still a draft. Drafts are invisible to clients by design.
The margin panel says LLM spend is unavailable. The cost ledger couldn't be read. That's a temporary read failure, not a statement that the work was free — retry the page.