Start with the business problem, not a feature list. What kind of user will use the system, how many times a day, and what happens today? An experienced team who grasps the purpose will suggest a simpler way to reach it; someone handed only a feature list will price exactly what you asked for.
Describe the scope as concrete flows: what the user does and what the system does in response. Just as important, write down what you are not building. An explicit list of exclusions prevents more disagreement during acceptance than any other single page. Mark too which items are decided and which may still change — the difference changes the price, and pretending everything is fixed helps nobody.
List the constraints. This means systems you must integrate with, the data you have and where it lives, devops services company regulatory obligations, expected load, which devices matter and infrastructure that is already decided. If a deadline is real, symfony or spring boot say why: a good team is usually able to resequence the work to protect it, but only if they know it exists.
Write down what the word done means feature by feature. Testable acceptance criteria do not need any formal notation: a short list describing what a user should be able to do will do. That one addition compresses the review at the end dramatically and eliminates the most common source of disputes.
One last thing, say what you expect back. Request a task-level breakdown, a written list of assumptions, whatever the team considers risky and a low number and a high number. Treat a wide range as a signal about the brief: it usually points to exactly which requirement is unclear. From there tighten that section and ask for a new estimate — the next version tends to be far closer to reality.