Write down the hard constraints. This means systems you must integrate with, the data you have and where it lives, regulatory obligations, user volumes, which devices matter and any technology you are committed to.
Ambiguous phrasing around code ownership is not a formality. The document needs to state in plain terms that all deliverables belong to your business as they are paid for.
One last thing, state what you want in the response. Require a task-level breakdown, the assumptions behind each number, whatever the team considers risky and an optimistic and a pessimistic figure.
Finally, say what you expect back. Ask for a task-level breakdown, the assumptions behind each number, whatever the team considers risky and an optimistic and a pessimistic figure.
Non-functional requirements quietly rewrite the number. An internal tool used by twenty people costs far less than the same feature set handling public traffic.
The biggest cost driver is never the technology stack — it remains how much is still undecided. Every open question in the specification becomes a contingency somewhere in the quote.
Ask where their numbers come from. A serious estimate arrives with a written set of assumptions, a breakdown by feature or module and a range rather than a single number.
Set out the scope as short scenarios: a walk through each important path. Every bit as useful, state explicitly what is out of scope. An explicit list of exclusions saves more argument during acceptance than almost anything else in the document.