An agent that returns the cheapest in-stock item is a sort function. A decision is a ranking under constraints, with the trade-offs named and the binding constraint identified.
A deadline and a budget are hard. A colour is soft. Passing them in the same bag produces recommendations that miss a flight to save four dollars. `constraints` are filters; `weights` are the trade-off, and they are separate fields for that reason.
POST /v1/decide
{ "intent": "headphones for a long-haul flight next Tuesday",
"constraints": { "budget_minor": 30000, "deliver_by": "2026-09-12",
"destination": { "postal_code": "10001", "country": "US" } },
"weights": { "price": 0.3, "speed": 0.4, "quality": 0.3 } }Users push back. When they do, the agent needs to know which constraint was binding — not to run the search again, but to say “if you can wait one more day, the Bose is better for a long flight”. That is the difference between an assistant and a search box.
"would_change_if": [
{ "condition": "deadline moved past 2026-09-14",
"then": "Bose QuietComfort Ultra — better comfort for a long flight" },
{ "condition": "budget raised above $349",
"then": "AirPods Max 2 — strongest ANC in the set" } ]Four things routinely reverse a ranking that price alone would have decided: shipping cost, delivery date against a deadline, return terms, and total cost of ownership where consumables exist. Each has its own endpoint because each one on its own is enough to make the cheap option the wrong one.
Stored constraints apply automatically. A buyer who said in March that they will not buy anything with a subscription does not have to say it again, and the recommendation can cite that as a reason — which is what makes it feel like it remembers rather than merely searches.
A price far below every other seller usually means a different item, a different region, or a listing that will be cancelled. Check `/v1/offers/{id}/risk` before acting without a human, and surface flags rather than silently skipping the offer.