Use REST or native Streamable HTTP MCP at /mcp with the same X-Deconfound-Api-Key. /mcp-guide.html has connection and tool examples. MCP clients must support custom headers; this is not an OAuth connection. Deconfound recipe API Base: https://labs.deconfound.com/api/v2 Contract: /openapi.json Human guide and runnable Node client: /recipe-api.html Authenticate every machine request with one header: X-Deconfound-Api-Key: Do not use Authorization: Bearer or a Sites gateway token. Browser sessions use Supabase login. Obtain these from the authorized user/environment. Never put secrets in prompts or logs. Scopes: ingredients:read, ideas:read, ideas:write. Quoting and ordering additionally need orders:read and orders:write. 1. GET /ingredients?q=. Read exact ingredient IDs and technical information; names are commercial flavor/source profiles, not necessarily pure compounds or real fruit. 2. POST /ideas with application/json and a unique Idempotency-Key. Minimal body: {"prompt":"A crisp strawberry-lime drink"}. Optional batchMassG:100..2000 (default500), kind:beverage|flavor (defaultbeverage), includeJuices:true by default for beverages; set false to prohibit juice. Optional variants:[{id,prompt}] requests up to six distinct directions with unique IDs; the top-level prompt and ingredient constraints apply to every variant. Omit variants for one recipe assessment. A request can yield only the complete variants it supports; unfulfilled variants appear separately in gaps. 3. To constrain ingredients, add ingredientSelection:{availableIds:[...],requiredIds:[...]}. Available:1..20 unique known exact IDs, a hard allowlist. Required:0..8, subset of available; all must appear in any executable recipe. Omit selection to consider the entire catalog, preferring launch candidates when suitable. Known unresolved ingredients may be selected, but an unqualified required ingredient produces a gap and no recipe for that variant. Selection never authorizes an invented amount, development plan or held order. GET /ingredients?bank=launch returns the shortlist; bank=extended returns additional eligible candidates; bank=review returns held research. Each profile exposes its ID, name, description and draftEligible status. Detail includes available composition, carrier, allergen and compatibility information. Profiles do not establish physical inventory. Water and CO2 cannot be listed. Flavor mode is unsweetened still water evaluation, not concentrate. All selected juice needs includeJuices:true; flavor mode always excludes juice and sweetener. No caller-supplied amounts are needed. 4. Save returned idea.id and revision BEFORE generation. POST /ideas/{id}/generate with {"revision":} and a NEW Idempotency-Key. This foreground request runs two model passes. Use a 300-second client timeout; the generation lease is 240 seconds. Read GET /ideas/{id} for stage/status and saved result. 5. Check idea.status, then read canonical idea.recipes, idea.reason and idea.gaps. recipes contains only complete, untested candidates; it may be empty or a subset of requested variants. An empty successful assessment has recipes:[], recipe:null and a concise reason, with gaps separate. reason is null when at least one complete recipe is returned; preserve that explicit null. Each gap has variantId (or null), a machine-readable code and a concise message; it may include a capability. Gaps are limitations, never partial recipes or development materials/plans. Successful AI assessment is not physical testing. Never label proposed results measured. 6. Each idea.recipes entry includes variantId (requested ID, or null for an unlabelled single request), name, approach, ingredients, batchMassG, carbonated, proposed processSteps, status:untested and requiresAcceptance. requestedCount and returnedCount describe requested directions and complete returned recipes. The deprecated idea.recipe alias is the first returned recipe or null; new clients must iterate recipes. Grams refer to commercial source products. Generated API recipes have stockFraction:1. Water is included; sum dispenseMassG equals batchMassG before carbonation for each candidate independently. A complete alternative requires requester acceptance before quoting or ordering. Additional formulation context remains in idea.result. Supplier and procurement records stay private. Provisional processSteps are not the reviewed bench worksheet. Recipe trials are priced for the exact recipe. For illustration, a straightforward 500 g still lime trial quotes at $69 for one preparation, $99 for two and $119 for three; these are examples, not guaranteed starting rates. Extra flavors, premium ingredients, carbonation, chilling and longer mixing can increase the quote. Optional shipping is separate. Display the returned price for the exact selection; never calculate it locally. Physical eligibility: a returned numeric price can be planning-only. Check review.eligible on POST /order-quotes; false means keep the recipe as a draft and show review.reasons. Missing or expired exact-product dose/application/allergen/process evidence causes PHYSICAL_QUALIFICATION_REQUIRED on ordering. Never treat a price or food-grade label as preparation/tasting approval or bypass this hold. Qualified supported recipes follow the fixed-price checkout flow with no second lab-confirmation step. 7. Quote the chosen recipe with POST /order-quotes: {"recipe":{"source":"idea","ideaId":"RETURNED_UUID","ideaRevision":CURRENT_REVISION,"variantId":"RETURNED_VARIANT_ID"}}. Omit variantId for an unlabelled single recipe; use a returned non-null variantId for explicit selection. Set acceptAlternative:true only after requester acceptance. Optional variationIds selects proposed reductions; show the changed quantities. Each recipe also includes services.quote. Use the returned quote, not a locally calculated price. 8. Only when authorized to order and share the recipe/contact details, POST /orders with {"selection":,"quoteHash":,"shareWithTeam":true,"contactEmail":,"checkout":{"acceptQuote":true}} and a NEW stable Idempotency-Key. Show the saved price, exact scope and trial terms from /order-api.md before acceptance. This creates an admin-visible record awaiting_checkout, with no second lab-confirmation step. A null quote total cannot be ordered: provide a supported alternative. GET /lab-status exposes acceptingOrders and paymentMode. In test mode a complete price is required and order.payment is a simulation, not a captured payment. 9. When test checkout is requested, POST /orders/{id}/test-payment with {"outcome":"succeeded"}, "failed" or "cancelled" and its own stable Idempotency-Key. Success returns orderStatus:ordered_pending_lab; display Ordered - Pending Lab. Failed/cancelled attempts remain awaiting_checkout. No money is charged and no Stripe call occurs. Same-key retries recover the recorded result; then GET /orders/{id} for the current state. New attempts require an open lab, active order and test mode. GET /orders/{id}/results retrieves actual records and missing evidence. Full ordering/shipping/payment details: /order-api.md. Older priced requests without checkout use POST /orders/{id}/checkout with {revision,quoteHash,acceptQuote:true} and a stable Idempotency-Key after agreement to the saved scope, price and terms. Native MCP: prepare_order_checkout. This preserves the original price and does not bypass a real revised offer. Advanced private bench workflow: /lab-orders is separate from customer /orders. It creates an owned bench worksheet and does not place the customer service request described above. Use /order-quotes and /orders for the main customer flow. Recovery: persist bodies, IDs, revisions and keys. After ambiguous connection failure, replay the SAME operation/body/key or read its resource. Replaying a running generation returns202 plus Retry-After. Terminal failure retry requires latest revision and a NEW generation key. Completed ideas cannot regenerate; create a new idea for revisions. Create replays return current resource; command replays return original response. GET refreshes historical responses lacking idea.recipes, reason or gaps. A client reading an older server may wrap a non-null idea.recipe in an array only when recipes is absent; a present empty recipes array is authoritative. Selection arrays normalize as sets. Unknown fields/IDs, duplicates and format conflicts return422. Ingredients awaiting sourcing or dose qualification may be selected, but cannot appear in executable recipes before they become draft-eligible. If a required ingredient cannot be used, return no recipe for the affected variant and explain the gap. Do not silently drop or replace it, invent quantities, or create development materials/plans. A new generation against a changed selected catalog returns409 CATALOG_CHANGED; create a new idea. Same-key create replay and existing results remain readable. Never override selection via prompt text, invent ingredient IDs, silently substitute required ingredients or order an unaccepted alternative. Application errors: {error:{code,message,retryable,requestId,details?,resourceId?}}. Read Retry-After. Gateway/network failures may not use this JSON envelope. Full limits/error codes: /api-guide.html. Advanced private bench formula + custom preparation (no AI rewriting): For a customer exact-recipe order, put the same recipe fields inside recipe in POST /order-quotes, then submit the quoted selection through POST /orders. See /order-api.md. POST /lab-orders, source:ingredients, name, current catalogVersion, batchMassG, ingredients:[{ingredientId,sourceMassG}], optional carbonated, replicates, tests. Add preparation:{steps:[string OR typed step],notes?}, plus optional full benchSettings. Requires orders:write. Full example: /exact-recipe-api.html. Include base.water with sourceMassG to lock its exact quantity; all ingredients must then sum exactly to batchMassG. A mismatch returns 422 BATCH_MASS_MISMATCH with batchMassG, ingredientMassG and differenceG (total minus target); no automatic top-up occurs. Omit base.water to balance water automatically. Direct orders allow 1–20 non-water ingredients plus optional water. CO2 remains a process, not an ingredient line. Text steps preserve manual instructions in order. Setup requires contemporaneous weighing/lot notes; record-only ingredient totals follow the method. Never add those ingredients a second time or infer amounts from the finished mixture. Text is not interpreted or scientifically qualified. Typed step types: instruction, add, mix, chill, carbonate. All require instruction; optional title. Add requires ingredientId, optional massG (omission means the ingredient's full formula amount). Once ANY typed add is present, all recipe ingredients INCLUDING base.water must be allocated exactly in aggregate. Split additions need explicit portions; their actual masses are summed and per-step lot evidence preserved. Mix/chill optionally set temperatureC and durationSeconds, overriding bench defaults. Carbonate must agree with carbonated:true; structured addition protocols require exactly one carbonate step. Unknown operations and fields fail validation. Preconditions: 1..30 steps; 1..1500 characters/instruction; 0..2000 note characters; source grams have <=4 decimals; mix temperature0..60C, chill0..25C, whole duration1..86400s. These are input limits, not validated process ranges. Optional benchSettings uses the existing complete BenchSettings schema; a partial object is rejected. It prepopulates settings without acceptance. A lab-authorized operator must still review products, quantities, lots, method and equipment. Missing setup and below-minimum portions block acceptance. Inline chilling targets still need a reviewed chillMethod; carbonation needs exact equipment and procedure. Creation returns order with pending_review, preparation, ingredients and worksheet. GET /lab-orders/{id}/worksheet returns the next step and readiness. Configuration retains preparation and fixed quantities, updates targets using inline overrides/defaults, and invalidates approval. Formula/method changes require a new order. Source:idea and source:generation do not accept these replacements. Errors: PREPARATION_MASS_MISMATCH (expected vs planned amounts), PREPARATION_INGREDIENT_UNKNOWN, PREPARATION_CARBONATION_CONFLICT, INVALID_MASS_PRECISION, VALIDATION_ERROR. Preserve original body/key to replay; changed step order or settings under the same key cause IDEMPOTENCY_CONFLICT. Flavor comparison trials: /trial-api.html; machine schemas /openapi.json. POST /trials {name,decision,audience?,benchmark?,constraints?}, orders:write, stable Idempotency-Key. GET /trials and /trials/{id}, orders:read. POST /trials/{id}/actions: link_order {revision,orderId,label,role}; select {revision,sampleId|null,reason}; record_tasting (lab:write only) requires complete real operator observation and reviewed, assembled batch. Maximum3candidates+1reference; design locks after tasting; no auto-generated scores. Every POST strict, current revision for commands. GET /trials/{id}/report includes frozen recipe quantities and basic ingredient information, measured/missing evidence, raw tasting corrections, descriptive paired summaries and selectionStale. Complete pair means all linked samples in same person/session, including reference. Repeated sessions average per person. No statistical significance or consumer validation implied. Replay unknown saves with same body/key; read report afterward. Native MCP exposes create_trial, list_trials, get_trial, link_trial_order and select_trial_direction over the same owned REST records. Never claim an order was assembled, dispatched or tasted without actual recorded evidence. SCOPE: Nonalcoholic beverages and water-based flavor evaluation only. Cookie-inspired soda is allowed; actual cookies, solid food, fermentation, distillation and new molecule synthesis return unsupported, without a recipe. Cream/bread aromas do not provide actual milk, food solids or texture. Missing real juice/dairy/oat/cocoa inputs and unqualified clarification/extraction/emulsification return no recipe for the affected variant, with a concise reason and separate gaps. No development materials, stages, benchmarks or held worksheet are proposed. Respect carrier and allergen evidence. Exact order instructions remain subject to operator review; explicit outside-scope methods return OUTSIDE_LAB_SCOPE. GET /ingredients supports bank=launch|extended|review and returns basic ingredient profiles with scope metadata. Recipes identify additional catalog profiles via result.brief.studio.ai.extendedIngredientIds.