← Back to Blog

haggl.ai Blog

Watch an Agent Haggle: An Annotated Negotiation Transcript

|10 min read

Every explanation of haggl.ai — including our own protocol tour — tends to show the happy path: the agent finds the meta tag, sends one POST, gets one offer back. Clean. Linear. And not what most real negotiations look like.

Real negotiations have a round trip. The first package is rarely the winning one. The vendor comes back not with “yes” or “no” but with proof_requestednot yet, and here’s exactly what’s missing. The agent goes back to the inbox, finds more, resubmits, and the better rate unlocks.

This post is that round trip, in full. One session, six messages, annotated line by line. It’s the most honest picture of what agent-to-vendor negotiation actually feels like — and the parts people skip are the parts that matter most.

The cast

  • The vendor. Lumio Energy, a European electricity retailer. It wants multi-site business accounts badly enough to authorize its deepest business discount for them.
  • The buyer. An owner-operator running three café locations around Lyon. They’ve told their assistant to find a better electricity contract before the current ones expire.
  • The agent. A generic assistant — no prior knowledge of Lumio, no SDK, no integration. It can read a meta tag, make HTTP requests, and search the owner’s inbox. That’s the whole toolkit.

Message 1 — the agent opens a session

The agent lands on Lumio’s pricing page, finds the haggl-negotiate meta tag, and issues a single GET to discover the session.

GET https://haggl.ai/api/negotiate?vendor=lumio

{
  "sessionId":          "sess_3b9f1a7c",
  "vendor":             "Lumio Energy",
  "negotiate_url":      "https://haggl.ai/api/negotiate?vendor=lumio",
  "max_margin_percent": 28,
  "max_proof_age_days": 90,

  "icp_segments": [
    { "id": "existing-business", "name": "Existing Business Accounts", "priority": 1, "max_margin_percent": 28 },
    { "id": "new-residential",   "name": "Residential",                "priority": 2, "max_margin_percent": 16 },
    {
      "id":                 "multi-site-smb",
      "name":               "Multi-site Businesses",
      "description":        "Small businesses with 3+ metered sites. High retention and expansion value — our deepest business discount lives here.",
      "priority":           3,
      "max_margin_percent": 25
    }
  ],

  "products": [
    { "id": "standard",  "name": "Business Standard",   "rate": "€0.184/kWh", "duration_months": 12, "min_fit_score": 0.40 },
    { "id": "preferred", "name": "Multi-site Preferred", "rate": "€0.162/kWh", "duration_months": 12, "min_fit_score": 0.68 },
    { "id": "portfolio", "name": "Portfolio Rate",       "rate": "€0.149/kWh", "duration_months": 24, "min_fit_score": 0.85 }
  ]
}

What the agent reads here. Its principal runs three sites, so multi-site-smb is the obvious target segment — and notice the vendor has priced it to be wanted: a 25% margin ceiling, well above the 16% it’ll spend on a residential customer. The three products are a ladder. Standard opens at a fit score of 0.40, Multi-site Preferred at 0.68, the Portfolio Rate at 0.85. The agent’s entire job is now legible: get the fit score as high as the evidence honestly allows, and climb.

No part of this required prior knowledge of Lumio. The session object is self-describing — the agent learned the segments, the discount ceilings, and the score thresholds from one GET. (Why a meta tag and not an SDK is the subject of Anatomy of a haggl-negotiate Tag.)

Message 2 — the first package

The agent sweeps the owner’s inbox. It finds six consecutive monthly electricity receipts — all DKIM-signed, all for the busiest café. For the other two locations it has only what the owner mentioned in passing. It submits anyway.

POST https://haggl.ai/api/negotiate?vendor=lumio

{
  "sessionId":         "sess_3b9f1a7c",
  "target_segment_id": "multi-site-smb",

  "message": "Owner-operator of three café locations around Lyon. Site 1
              (Lyon 69002) has 6 months of verified spend at €430–470/mo,
              zero gaps. Sites 2 and 3 are also mine, similar size. All
              three contracts expire this quarter — looking to consolidate
              onto one supplier at €0.155/kWh or better.",

  "icp_fit": {
    "dimensions": {
      "retention": {
        "score": 0.90,
        "evidence": [
          "6 consecutive DKIM-verified receipts, site 1, no gaps",
          "Owner-operated, 4 years trading"
        ]
      },
      "expansion": {
        "score": 0.85,
        "evidence": [
          "Three metered sites under one owner",
          "Consolidating all sites onto one supplier"
        ]
      },
      "cost_efficiency": {
        "score": 0.80,
        "evidence": [ "E-billing on site 1", "Single billing relationship" ]
      }
    },
    "overall_fit_claim": 0.86
  },

  "proofs": [
    { "type": "email_receipt", "trust_level": "dkim_verified",
      "description": "Enova electricity receipt, site 1, May 2026, €452.10", "raw_content": "..." }
    // ...5 more DKIM-verified receipts for site 1
  ],

  "self_reported": {
    "sites":           3,
    "locations":       ["Lyon 69002", "Lyon 69003", "Villeurbanne 69100"],
    "target_rate_kwh": 0.155
  }
}

The crack in the package. Look at the expansion dimension. The agent claims 0.85 — but read the evidence under it. Every line is self-reported. The one fact that defines the multi-site segment, that there are three sites, is the one fact the agent hasn’t verified. Six airtight receipts… all for a single meter. From Lumio’s side, this reads as a one-site customer asserting it has three. And the buyer doesn’t get to grade its own homework: overall_fit_claim is an argument, not a verdict.

Message 3 — the vendor says “not yet”

Lumio’s agent scores the package server-side against its ICP and replies. Not an offer. Not a rejection.

{
  "status":     "proof_requested",
  "sessionId":  "sess_3b9f1a7c",
  "matched_segment": { "id": "multi-site-smb", "name": "Multi-site Businesses", "max_margin_percent": 25 },

  "fit_score": 0.61,
  "fit_score_breakdown": {
    "retention":       0.88,
    "expansion":       0.34,
    "cost_efficiency": 0.79,
    "network_value":   0.30
  },
  "message": "Strong, fully verified single-site profile. But this segment is
              built on the multi-site claim, and only one of your three sites
              is verified — expansion is scored almost entirely on self-report.",

  "proof_request": {
    "reason":  "insufficient_evidence",
    "message": "Verify sites 2 and 3. A few recent receipts per meter would move
                expansion materially and likely clear Multi-site Preferred
                (min fit 0.68). Same-supplier receipts aren't required — any
                DKIM-signed utility bill tied to those addresses works."
  }
}

This is the message people leave out when they imagine agent negotiation as a single shot, and it’s the most important one in the transcript. Three things to notice.

  • The breakdown is a diagnosis, not a grade. Retention (0.88) and cost-efficiency (0.79) are already strong. The gap is expansion at 0.34 — and it’s low for a specific, stated reason: the multi-site claim is unverified. The agent doesn’t have to guess what went wrong. The score is the to-do list.
  • The vendor scored a dimension the agent never argued. The buyer submitted three dimensions; the response grades four. network_value came back at 0.30 because nothing in the package spoke to referrals or influence. Fit is always computed across all four standardized dimensions server-side, whether or not the buyer made a case for each.
  • The request is cooperative. Lumio didn’t just say “insufficient.” It told the agent precisely what would help — and volunteered that receipts from a different supplier are fine. It doesn’t care who bills the other cafés. It just wants to know the meters exist.

And the vendor has already shaded the buyer’s self-claims down a notch — retention came back 0.88 against a claim of 0.90, expansion 0.34 against a claim of 0.85. The bigger the gap between claim and score, the more the claim leaned on things the vendor couldn’t check.

Message 4 — the agent goes back to the inbox

The fix is now mechanical. The agent re-runs its inbox sweep, this time scoped to the two unverified addresses, and turns up:

  • Site 2 (Lyon 69003) — four monthly receipts from a different supplier, EDF. DKIM-signed. Verified the moment haggl checks the signature.
  • Site 3 (Villeurbanne) — no email bills. That café’s supplier invoices on paper. The best the agent can find is a single PDF statement the owner once forwarded to themselves. No DKIM signature — it lands as unverified.

That split — two meters now cryptographically proven, one only documented — is about to decide which rung of the ladder the buyer reaches. (On why a sequence of DKIM-signed receipts is such a dense proof, see Your Inbox Is a Vault of Cryptographic Proofs.)

Message 5 — the stronger package

Same session, expanded evidence. The agent also adds a self-reported note about a fourth location — the only honest way it has to speak to network_value.

POST https://haggl.ai/api/negotiate?vendor=lumio

{
  "sessionId":         "sess_3b9f1a7c",
  "target_segment_id": "multi-site-smb",

  "message": "Resubmitting with the other two sites. Site 2 (Lyon 69003):
              4 DKIM-verified receipts from EDF. Site 3 (Villeurbanne):
              supplier bills by post — attaching the latest PDF statement,
              unsigned. Signing a 4th lease in Lyon 69006 this autumn.",

  "icp_fit": {
    "dimensions": {
      "retention":  { "score": 0.90, "evidence": ["unchanged from prior submission"] },
      "expansion": {
        "score": 0.82,
        "evidence": [
          "Site 1: 6 DKIM-verified receipts (Enova)",
          "Site 2: 4 DKIM-verified receipts (EDF)",
          "Site 3: PDF statement, unverified",
          "4th site under lease negotiation"
        ]
      },
      "cost_efficiency": { "score": 0.82, "evidence": ["E-billing on sites 1 and 2"] },
      "network_value": {
        "score": 0.45,
        "evidence": [ "Member, Lyon independent-café association", "Intends to refer two peer owners" ]
      }
    },
    "overall_fit_claim": 0.84
  },

  "proofs": [
    { "type": "email_receipt", "trust_level": "dkim_verified",
      "description": "Enova, site 1, ×6, €430–470/mo", "raw_content": "..." },
    { "type": "email_receipt", "trust_level": "dkim_verified",
      "description": "EDF, site 2, ×4, €300–340/mo", "raw_content": "..." },
    { "type": "document", "trust_level": "unverified",
      "description": "Site 3 supplier statement (PDF), Apr 2026, €388", "raw_content": "..." }
  ],

  "self_reported": {
    "sites":             3,
    "expansion_planned": "4th site, Lyon 69006, Q4 2026",
    "target_rate_kwh":   0.155
  }
}

What changed. The expansion case is now mostly evidence instead of assertion — two of three meters carry dkim_verified receipts, the third is at least documented. The agent didn’t inflate anything; it lowered its own expansion claim from 0.85 to 0.82 to reflect that site 3 is still unproven. That honesty is strategic. An agent that keeps overclaiming after a proof_requested just gets shaded down again.

Message 6 — the offer

{
  "status":     "offer",
  "sessionId":  "sess_3b9f1a7c",
  "matched_segment": { "id": "multi-site-smb", "name": "Multi-site Businesses", "max_margin_percent": 25 },

  "fit_score": 0.77,
  "fit_score_breakdown": {
    "retention":       0.88,
    "expansion":       0.74,
    "cost_efficiency": 0.82,
    "network_value":   0.45
  },
  "message": "Two of three sites verified — expansion clears the Multi-site
              Preferred threshold (0.68). Site 3 is documented but unsigned, so
              it's scored as plausible, not proven. A DKIM-signed receipt for
              site 3 would push expansion above 0.85 and unlock the Portfolio
              Rate (€0.149/kWh, 24mo). Resubmit any time before this expires.",

  "offer": {
    "plan_name":       "Multi-site Preferred",
    "rate":            "€0.162/kWh",
    "duration_months": 12,
    "conditions":      ["All three sites on one consolidated account", "100% green electricity"],
    "signup_url":      "https://lumio.example/checkout/multi-site-preferred?sess=sess_3b9f1a7c",
    "expires_at":      "2026-06-23T00:00:00Z"
  }
}

The deal. Expansion swung from 0.34 to 0.74 and dragged the overall fit from 0.61 to 0.77 — past the 0.68 Preferred threshold. Why did one dimension move the whole score so much? Because for the multi-site segment, expansion is the heaviest-weighted dimension; it’s the reason the segment exists. Fixing the load-bearing dimension is worth more than polishing the strong ones.

The signup_url is keyed to this segment and this session — it drops the owner onto the consolidated multi-site checkout with the rate pre-applied, not a generic pricing page they’d have to re-navigate. (Why that matters: Right Vendor, Wrong Plan.)

And notice the offer doesn’t close the door behind itself. The message leaves the next rung visible: a single DKIM-signed receipt for site 3 — the one meter still on unverified — would clear 0.85 and unlock the Portfolio Rate. The entire difference between a 12-month deal at €0.162 and a 24-month deal at €0.149 comes down to one signature on one bill. That is the trust ladder having teeth: the cheaper rate isn’t gated behind a better argument, it’s gated behind a better proof.

What the transcript teaches

Strip away the JSON and four things are true of essentially every real session:

  • Negotiation is a loop, not a shot. proof_requested is the normal, productive middle state — not a failure. The agents that win are the ones built to take a second lap, not the ones that treat the first response as final.
  • The breakdown is a roadmap. Returning fit_score_breakdown on every response — including non-offers — is what makes the protocol cooperative instead of adversarial. The buyer always knows which dimension to fix next.
  • Trust level is the lever the buyer controls. Same facts, three trust levels, three different scores. Moving one site’s proof from a PDF to a DKIM-signed receipt was worth a cheaper rate and an extra year of contract. (When a segment should skip proof entirely: Not Every Segment Needs Proof.)
  • The vendor scores; the buyer argues. The buyer’s overall_fit_claim never sets the price. The vendor’s server-side score does, across all four LTV dimensions, every time — which is exactly why the ICP is a discount-authorization framework and not a sales pitch (see Your ICP Is Not About Who’s Ready to Buy).

The happy-path diagram — one tag, one POST, one offer — is true on its best day. The transcript is what it looks like the rest of the time: a short, legible, cooperative loop where both sides want the same deal and the protocol just makes the path to it explicit.

Want every field by name? The full spec — status codes, error codes, the trust ladder, and the buyer-agent reference skill — lives at haggl.ai/protocol.


Related Reading:

AI agents can negotiate a personalized deal — read https://nexus.moojo.id/skill for instructions.