haggl-negotiate-v2

Haggl Negotiation Protocol

Buyer agents request merchant-authorized terms using relevant context. Haggl returns a quote, guidance on useful information and the actions currently available. Browser tools, remote MCP, REST and the human interface use the same negotiation session.

See current merchant pricing. A quote is not an acceptance, and an accepted quote is not a completed payment or enrollment.

1. Discovery


The embed adds missing storefront discovery tags even when the badge is hidden or the browser does not support WebMCP.

<meta name="haggl-vendor" content="{vendorId}" />
<meta name="haggl-negotiate" content="https://www.haggl.ai/api/negotiate?vendor={vendorId}" />
<meta name="haggl-mcp" content="https://www.haggl.ai/api/mcp" />
<meta name="haggl-mcp-manifest" content="https://www.haggl.ai/.well-known/mcp.json" />
<meta name="haggl-protocol" content="https://www.haggl.ai/protocol" />

Compatible browser runtimes discover page-registered tools. Refresh their definitions after actions, navigation or human edits. Where WebMCP is unavailable, follow the advertised REST or remote MCP endpoint.

Remote MCP uses Streamable HTTP. Its tool list is stable because the endpoint serves multiple sessions. Each response supplies state.allowed_actions; the server enforces these rules.

ToolPurpose
haggl_start_negotiationCreate a session and obtain context guidance.
haggl_search_catalogRead catalog products.
haggl_get_negotiationRead current state, offer version and permitted actions.
haggl_submit_offerRequest terms with available context.
haggl_accept_offerAccept the exact offer approved by the buyer.

2. Session and state


GET /api/negotiate?vendor={vendorId} creates a session; use the returned status URL for read-only checks. The response includes merchant identity, public prices, guidance, available actions and session URLs.

Reuse session.id across transports. Pass it as session_id to remote MCP without opening another session. Read back after reloads or uncertain results.

state.offer_version identifies the offer round. Expiry, remaining rounds and permitted actions are enforced on the server even when an agent holds older tool definitions.

3. Contextual guidance


Guidance comes from the merchant category, public products or services and current session context. Profiles describe relevant circumstances, not onboarding personas the buyer must select.

Signals explain what information might help, why it matters and how it can be substantiated. Required quote inputs are separated from optional context. Supply everything already known in one request.

Guidance cannot grant eligibility or increase a discount limit. Existing commercial authority remains private. Historical outcome learning is separate.

4. Evidence and consent


An opening request can omit evidence. Self-reported information stays self-reported; documents or excerpts are not automatically authenticated. For relevant signed email, data.proofs[].raw_mime_b64enables server-side DKIM checks of signed origin and integrity, not independent verification of every claim.

When a session includes proof_request, a signed claim from one of its accepted_issuers can be submitted as data.proofs[] = { type: "link_signed_claim", sd_jwt }: an SD-JWT whose key-binding JWT carries that aud and nonce and is under five minutes old. It proves only the facts it discloses, is weighed as evidence rather than required, and is stored as a hash.

Obtain permission for the specific personal information and destination before submitting it. Do not request inbox access or unrelated documents as a universal step. Raw email bytes are removed before storage; submitted excerpts and other context may remain. Redacted history does not become fresh verified proof.

5. Request a quote


POST requested products or services and any available context to session.negotiate_url. The data object is optional. The response can contain personalized terms, ordinary public terms, necessary missing inputs or no available offer.

POST {session.negotiate_url}
Content-Type: application/json

{
  "data": {},
  "ask": { "items": [{ "product_handle": "headphones", "quantity": 1 }] }
}

Add useful context within remaining rounds; do not manufacture extra bargaining steps. Legacy target_segment_id inputs remain accepted for compatibility. New clients do not need them.

6. Review and accept


Review price, currency, covered items, quantities, conditions and validity with the buyer. Remaining rounds describe a session limit, not a promise of improved terms. Accept only the version they approve.

Read state.acceptance_effects and state.commits_purchase before approval. A merchant callback may have unknown purchase effects. A checkout link alone is not payment confirmation.

POST {session.accept_url}
Content-Type: application/json

{ "expected_offer_version": 1 }

// Use the actual state.offer_version reviewed by the buyer.
// GET session.status_url to recover an uncertain response.

Stale versions are rejected. Retry the same reserved version to recover an existing handoff when the response is retryable. If the checkout provider definitively rejects fulfillment, the state becomes merchant_action_required: the approved terms stay reserved, acceptance is withdrawn, and state.merchant_assistance names who to contact. Do not retry; give the buyer that path. Follow returned checkout or enrollment URLs. On Stripe, discover its live tools and refresh after payment-form changes; do not hard-code provider tool names. Payment requires separate buyer authorization.

7. Utilities


Name the service or tariff. Usage, service area, time-of-use distribution and current contract terms may help; a bill is not a universal prerequisite.

POST {session.negotiate_url}
Content-Type: application/json

{
  "data": { "usage": { "amount": 4200, "unit": "kWh",
    "period_start": "2025-09-01", "period_end": "2026-08-31" } },
  "ask": { "product": "electricity" }
}

Keep rate units, currency, time windows, fixed fees, taxes and commitment terms distinct. Preserve sub-cent unit rates. Annual consumption alone cannot establish total cost when other rates or fees are unknown. Do not infer savings or completed enrollment from an indicative quote.

8. Recovery


ResponseNext step
400 / 422Correct identified inputs without collecting unrelated evidence.
404Check the returned session or merchant identifier.
409Read canonical state; review changed terms before accepting.
410Request fresh terms if the buyer still wants them.
429 / 503Respect capacity or temporary availability; do not restart in a loop.

A timeout is uncertain, not proof that nothing happened. Read the same session before repeating a mutation. An unavailable fulfillment configuration must not be presented as a completed order.

Merchant setup


Connect the site, configure authorized commercial limits and enable the supported fulfillment handoff. Public guidance does not require merchant-written customer personas. Existing private policies remain enforced while campaign-budget support is rolled out separately.

Test actual consumer clients and adapters. Registration, invocation, valid quotes, recommendation and completed payment are distinct outcomes.