Begin with the problem you are solving, not a feature list. What kind of user will use the system, offshore software development company how often, and how is the job done today? A vendor who understands the goal often proposes an alternative that costs less; a team that receives only the requirements as given can only price your assumptions along with the work.
Define what is included as short scenarios: who does what, and what happens next. Equally important, state explicitly what the first release deliberately excludes. An explicit exclusion list prevents more argument during acceptance than almost anything else in the document. Mark too which is better symfony or spring boot items are decided and which may still change — estimators price uncertainty, and pretending everything is fixed helps no one.
List the constraints. This means existing systems the software has to talk to, the data you have and where it lives, security and compliance rules, expected load, which devices matter and any technology you are committed to. If a deadline is real, say what depends on it: a team is usually able to rearrange the plan to protect it, provided they hear about it early.
Say what done means feature by feature. Testable acceptance criteria do not require any formal notation: app store optimization agency a short list setting out what must be true when the feature works is sufficient. That one addition reduces the sign-off process dramatically and removes the most common source of disputes.
Finally, ask for a specific format. Request a breakdown by feature or module, the assumptions behind each number, the risks the team sees and a range rather than a single figure. Read a wide range as useful information rather than evasion: it normally identifies exactly which requirement is unclear. At that point rewrite that part and request a revised number — the second estimate is the one worth planning around.