# Final offers

This is a compatibility protocol for existing orders with real revised offers. New orders only accept fully priced supported recipes and proceed directly to checkout. Fully priced supported requests can use [direct checkout at the saved quote](/order-api.md#simulated-test-checkout), without waiting for another offer. Do not create a new review request to enter this path. For historical orders already carrying an offer, the customer explicitly accepts that particular offer before checkout. Advanced work release can use a paid, explicitly accepted direct quote or a historical accepted offer; actual source, method and equipment checks still apply.

1. For normal orders use `/order-api.md`. A null total cannot be ordered; offer a supported alternative.
2. For an existing priced request with no revised offer, use `POST /api/v2/orders/{id}/checkout` after explicit saved-quote acceptance. Continue below only when an actual offer already exists.
3. GET `/api/v2/orders/{id}/offers`. `current` is the active offer; `offers` retains prior versions. No current offer is not a reason to wait for lab confirmation; a supported priced request can use saved-quote checkout. A missing legacy brief or acceptance is explicitly `not_recorded`.
4. Show the whole offer: original request, alternative/change explanation, exact recipes and sample scope, one included iteration, criteria and assessment methods, trial/shipping/tax/total, report date, expiry, cancellation/rework/shipment terms and contact.
5. Only after explicit agreement, accept the current unexpired offer:

```sh
curl "$DECONFOUND_BASE/api/v2/orders/$ORDER_ID/offers/$OFFER_ID/accept" \
  -H "X-Deconfound-Api-Key: $DECONFOUND_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: offer-accept-unique-stable-key' \
  --data '{"revision":3,"offerHash":"RETURNED_OFFER_HASH","confirm":true}'
```

Use the revision from the offer view. Response: `{offer,order}`. Reuse the identical body/key after an ambiguous response. A changed key/body, outdated revision, expired/superseded/revoked offer, source hold or paused intake prevents new acceptance. The API never treats the original idea request as acceptance of a later alternative.

6. In server test mode, acceptance initializes a pending simulated payment bound to the accepted offer ID/hash and total. POST `/api/v2/orders/{id}/test-payment` with `{"outcome":"succeeded"}` and a separate stable idempotency key. No card, payment provider or money is involved. Acceptance or simulated success does not release work.
7. The operator separately verifies received lots, equipment, precision and methods, reserves ingredients and releases work. Results arise only from recorded evidence. The accepted report date remains `snapshot.delivery.originalReportDueOn`; revised forecasts appear in `reportDueOn` and the timeline.

Native MCP equivalents: `quote_order`, `place_order`, `get_order_offers`, `accept_order_offer`, `get_order_results`. Acceptance tool arguments are `{orderId,offerId,idempotencyKey,request:{revision,offerHash,confirm:true}}`. Agents must obtain the requester's explicit authorization. Operator offer/release commands are never exposed as MCP tools. Simulated payment uses REST/browser.

## Operator contract

GET/POST `/api/v2/admin/orders/{id}/offers` requires an authorized operator browser session. GET returns editable defaults. Issue `{action:"issue",revision,...defaults,confirm:true}` after choosing scheduledBenchOn, a report date and 2–4 criteria. The bench date cannot be later than the report date; offer expiry is on or before the bench date. Instrument criteria require a finite matching min/max target and reviewed instrument/method/verification. Verified BenchSettings may resolve a precision limit; they cannot authorize unsupported food or unsafe doses. Explicit formula changes require an alternative and change explanation. Shipping exceptions need a bounded reviewed sample mass and allowance or a report-only alternative.

The server preserves its margin floor and computes the final total from explicit trial, shipping and tax components. The current pilot is simulated; tax treatment must be stated, never silently presented as configured tax collection. Work estimates are planning data, not measured labor or a guarantee of availability.

Revoke an unaccepted offer with `{action:"revoke",revision,offerId,reason}`. Every command needs an immutable key. Accepted, released or started work cannot be overwritten. Create a linked request for changed scope. Already-started legacy work can finish only under its migration record; this does not invent customer acceptance. For an unstarted legacy simulated payment with identical scope/price, the original receipt is preserved and a customer's actual acceptance now creates a new offer-bound simulated checkout.

## Work calendar

The operator calendar starts at six preparations and 180 estimated bench minutes per day in America/Los_Angeles. Configure it with GET/POST `/admin/capacity`. Estimates are planning numbers, not measured labor. Operator-issued offers temporarily hold the exact planned work through expiry. Acceptance retains the allocation. Free requests and idea generation do not book slots. Atomic checks prevent simultaneous offers from exceeding either budget. Lowering a budget does not erase existing commitments; it prevents new or over-budget acceptance until the calendar is resolved.

Unknown or overdue active legacy work must be allocated before new slots are promised. Migration preserves known work dates, otherwise uses a recorded report date provisionally; missing time is conservatively allocated 180 minutes. This does not fabricate acceptance. A reschedule retains original accepted dates and records a separate current bench forecast/reason plus a manual notification task. Completed work and started cancellations retain the day’s consumed allocation; pre-start cancellation releases it. Finishing or cancelling work never reopens an operator-paused lab.

## The returned report

GET `/orders/{id}/results` returns every preparation plus the assessment of each accepted criterion for each version. `assessment_pending` means recorded preparations still need a current conclusion. Read the explicit verdicts and omission reasons; `reported` never means every goal passed. Corrections preserve history and invalidate outdated conclusions. The first real publication date remains unchanged across corrections. See [trial assessments](/service-assessments.md) for response fields, statuses and operator preview/publication rules.
