---
title: "Quotes"
slug: workspace/quotes
url: https://projectri.com/docs/workspace/quotes
section: workspace
audience: workspace
app_route: "/[slug]/[user]/quotes"
permissions: [quote.view, quote.send, quote.withdraw, client.contract]
plan: commercial.quotes
mobile: "/quotes"
updated: 2026-09-08
source: Projectri documentation
---

# Quotes

What is out with clients and what they did with it — send a quote on a private link, watch it be opened, and turn the accepted one into a statement of work.

![Quotes](https://projectri.com/docs-shots/workspace-quotes.png)

## What it is

A quote is the document a client reads. It is made from an estimate, and making
it freezes a snapshot of the lines as they stood — the estimate goes on being
revised and re-priced, and the quote the client is holding does not move.

This list is built around the question sales actually asks, which is not the
money: *has the client opened it, and how long ago*. So the total is one column,
and the four to its right are all about the client's behaviour.

## How to get there

Quotes is in the main navigation and needs `quote.view`. Like the other
commercial keys it is excluded from the blanket viewer grant and is granted per
role at [Admin → Permissions](/docs/admin/permissions).

Sending needs `quote.send` — the one that cannot be taken back. Withdrawing
needs `quote.withdraw`. Drafting a statement of work from an accepted quote
needs `client.contract`. Every write needs the `commercial.quotes` plan feature;
reading the list does not.

There is no "new quote" button here, and the empty state says why: *a quote is
made from an estimate — open one and send it*.

## How to use it

### Make a quote

1. Open an estimate and press **Create quote**. It is offered on a draft or a
   sent estimate.
2. The quote takes its title, currency, client and validity date from the
   estimate, and freezes the lines as a snapshot. You land here.
3. Versions count per estimate, so re-quoting a revised estimate reads as "v2 of
   what we offered them".

### Send it

1. Press **Send to the client** on the row.
2. Sending renders the PDF **once**, hashes those exact bytes, stores them, and
   mints an unguessable link at `/q/<token>`. After that, none of the three can
   change.
3. Recipients get an email with the link, rendered in their own language rather
   than the sender's. The link lives until the quote's **Valid until** date, or
   60 days when it names none.
4. A quote that has already been sent cannot be sent again — a second render
   would produce a document that no longer matches the one the client holds a
   hash of. **Send again with a fresh link** is offered on an expired quote, and
   mints a new token so the lapsed link stays dead.

### Hand the link over again

1. Press **Copy the client link**. It copies rather than opens, on purpose:
   opening `/q/<token>` from inside the workspace records a view and can flip
   the quote from Sent to Viewed, so you would be telling yourself the client
   had read it.
2. The button is ungated. The link has already been mailed to the client by
   whoever sent it, and re-handing it to them is not an edit.

### Watch what the client does

1. **Sent** is how long ago it went out. **Opened** is how long ago it was first
   opened and, when there is more than one, how many times — one open is a
   glance, five is a document being circulated internally.
2. **Viewed** is a status you can filter on, not a timestamp in a tooltip. The
   difference between "no answer" and "opened four times and no answer" is the
   difference between resending the email and picking up the phone.
3. **Valid until** marks the row *lapsed* once the date has passed. Nothing
   sweeps quotes to Expired, so a Sent quote past its date is still Sent — but
   the public page will refuse a signature on it.

### Withdraw one

1. Press **Withdraw** and confirm. It is offered on a Sent or Viewed quote only.
2. The client's link stops working immediately — the token is cleared, not left
   to expire — and the quote cannot be sent again. The next step is a new
   version.
3. The document, its hash and the view history all stay. A withdrawal is a thing
   that happened, not a thing that unhappens.
4. An accepted or declined quote cannot be withdrawn. By then it is a decision
   with weight, and retracting it in our records alone would leave the two
   parties holding different accounts of the same deal.

### Turn an accepted quote into a contract

1. Press **Draft the SOW from this quote** and confirm.
2. It lands as a **draft** contract carrying the quote's value, currency, rate
   card, dates and the quote PDF. Nothing is sent to the client. A quote being
   accepted is the client saying yes; a contract existing is us saying we are
   ready to be held to it, and those are not the same moment.
3. A quote can only be converted once. Afterwards the row offers **Open the
   contract this became** instead.

### What the client sees on the public page

1. `/q/<token>` opens with no sign-in, no app chrome and no navigation. The
   reader may never have a Projectri account, and anything that looks like a
   product to log into invites them to hunt for a password instead of reading
   the quote.
2. It shows your workspace's name or logo, the quote number and version, the
   intro, the lines grouped into the sections you wrote them in, hours,
   subtotal, discount, total, terms and the validity date. It carries **no cost
   and no margin** — those fields are simply not in the snapshot, so the
   omission is not a permission check that could be got wrong later.
3. Opening it records a view. The first open moves the quote from Sent to
   Viewed. Reading a decided quote again does not un-decide it.

### How the client accepts or declines

1. The client presses **Accept this quote**, then types their **full name**,
   **email address** and an optional **job title**.
2. The page states what it is doing: typing your name records your acceptance,
   and your name, address, job title, the date and time and the exact document
   you are accepting are stored as the record. It also says plainly that this is
   a record of acceptance, not a legally certified electronic signature — a
   client whose organisation requires one is told to say so first. For a
   certified signature, send the document from the contract's **Signatures** tab
   instead.
3. Declining asks for a **reason** from a fixed list — price, timing, scope,
   going with someone else, no decision for now, or something else — plus an
   optional note. A decline without a reason is a lost deal nobody learns from.

### Where the signature is stored

1. Accepting or declining writes a signature record against the quote holding
   the action, the signer's name, address and title, any decline reason and
   note, the client's network address and browser, the timestamp, and the
   **SHA-256 of the exact PDF that was sent**. That hash is what ties the
   signature to a document rather than to a total that has since moved.
2. The record is returned by the quote API; the workspace also gets a
   notification to the quote's owner and an audit entry.
3. Answering twice is harmless: the same decision is returned as already
   recorded rather than written again, and only a genuine first decision rings
   anybody's bell.

## What it affects

- **The estimate.** Accepting or declining moves the underlying estimate to the
  same status. Leaving it behind would mean the pipeline still showed an open
  deal the client has already answered.
- **Nothing is provisioned.** A client accepting a quote creates no project, no
  task and no contract. The next step is somebody inside the workspace pressing
  **Draft the SOW from this quote**, or converting the estimate to a project.
- **Notifications.** The quote's owner is told, on both doors — the tokened link
  and the portal — and only they. A quote has exactly one person whose next move
  it is.
- **The expiry reminder.** A quote with a validity date gets one reminder three
  days before it lapses, mailed to whoever it was last sent to and written as a
  portal notification to the client's contacts. Re-sending re-arms it.
- **The client portal.** A client with a portal login sees the same quote at
  [Portal → Quotes](/docs/portal/quotes) and can accept or decline it there.
  Both doors enforce the same rules.

## On mobile

The **Quotes** screen in the Expo app is the same list and the same four
actions, decided from the same table so a control never appears on one surface
and not the other. The link action differs by surface honestly: the web copies
the URL, the phone opens the share sheet, because on a phone that link is going
straight into a message. Authoring a quote stays on the web — its wording is
written beside the client's email, and sending freezes the PDF, its hash and its
link together.

## Limits and gotchas

> [!WARNING]
> **Withdraw is terminal.** The link dies the instant it lands and the quote
> number is spent — a withdrawn quote can never be sent again. Use it when the
> number in the document was wrong, and issue a new version.

- Do not open `/q/<token>` yourself to check it. It records a view and can move
  the status to Viewed.
- A dead link is answered with a flat "not found" for wrong, expired and
  withdrawn alike. Saying "expired" would confirm the token was real.
- Expiry is evaluated when the link is opened, not by a nightly job. A quote
  that lapsed at midnight is lapsed whether or not anything ran.
- "Valid until the 30th" means the whole of the 30th. Acceptance is refused from
  the 31st.
- Accepted and declined are terminal. A client who changes their mind gets a new
  version, not a rewritten one.
- If the workspace has no blob storage configured the PDF bytes may not be
  stored, but the hash always is. Losing the bytes is recoverable; losing the
  tie between a signature and a document is not.
- Every money field on the wire is in **minor units**, including the snapshot
  the client's page renders from.

## Related

- [The estimate builder](/docs/workspace/estimate) — where a quote is made.
- [One contract](/docs/workspace/contract) — what an accepted quote becomes, and where certified e-signature lives.
- [Portal → Quotes](/docs/portal/quotes) — the same document for a client with a login.
- [Notifications](/docs/features/notifications) — what an acceptance rings, and for whom.

## Related

- [The estimate builder](https://projectri.com/docs/workspace/estimate.md): A spreadsheet-shaped grid for pricing work — sections, lines, resolved or pinned rates, discount, margin, and the buttons that send it, revise it, quote it or turn it into a project.
- [One contract](https://projectri.com/docs/workspace/contract.md): A single agreement end to end — terms, rate card, burn, billing and revenue schedules, projects, documents, amendments, retainers and signatures.
- [Quotes](https://projectri.com/docs/portal/quotes.md): Every quote your supplier has sent you, with its reference, version, date and total — the same documents as the emailed links.
- [Notifications](https://projectri.com/docs/features/notifications.md): What Projectri tells you about, on which of the five channels, what you can turn off, and the difference between a channel and a subscription.
