I've seen it work well when approached in 2 phases:
Phase 1) Inception (timeboxed)
A timeboxed inception period with the client to scope the project. (A one month intense inception for a project estimated to last a year is about right.)
Outputs to this phase are a full backlog of sized user stories, an estimation of flow rate per dev pair, and parameters to estimate project costs based on the number of developers and overheads of having larger teams.
The inception provides a useful budget estimation that can be tracked throughout phase 2, a clear shared vision for both client and supplier, plus the option for either side to walk away. This isn't upfront design, the stories have just enough detail for a lead dev / tester to assign relative sizes.
Phase 2) Delivery (time and materials)
A delivery contract based on time and materials, with budget estimates based on the outputs from the inception phase. The trust built up in phase 1 is vital to making this work. Because phase 1 delivered relative sizing of the entire backlog, by regularly measuring actual flow it is possible to easily and frequently report projected flow rate for the rest of the backlog with increasingly accurate estimates of budget and delivery date. The supplier should be contracted to report these stats at least every 2 weeks, with the option for the client to walk away at any point.
By paying for time and materials, the client is free to change the scope and proirity of the backlog, and is therefore in control of the budget. They are encoraged to prioritise their highest priority / highest risk stories first, and by allowing them to walk away whenever they like they should experience a positive return on investment at all times.