Ad Context Protocol

How Bidhalo lives
on the Ad Context Protocol.

Bidhalo is the agent layer that rides on top of ACP. We don't replace the protocol — we route its traffic, reason over the signals it carries, and record every move back into a tamper-evident ledger that any publisher can replay. This page is the message-by-message map.

Where Bidhalo sits

Sits on top of your existing DSP / SSP. Sits on the Ad Context Protocol.

Bidhalo doesn't sit above the protocol in a vendor console. It sits on it — the same place the DSP and the SSP already exchange intent. Bid requests flow through it, bid responses flow back through it, and every move that crosses the boundary leaves a record on the other side.

The result is a system-of-record that's actually on the protocol layer: the same audit entry the agent emitted is the same entry the publisher's own ops surface reads, the same entry a regulator reads, the same entry a replay reads — no separate Bidhalo-only black box.

The four classes of signal

  • Bid requests — incoming supply traffic the agents reason over.
  • Bid responses — outgoing clearing prices the agents set.
  • Audit events — every reasoning step the agents emit, recorded as a typed ledger entry.
  • Policy flags — IVT and AdCP policy violations raised inline, with the rule that fired.

ACP messages

Which messages Bidhalo's agents emit — and which they consume.

Four message classes make up the protocol surface between Bidhalo and the rest of the stack. Two traverse the boundary; two originate inside Bidhalo and are emitted for the publisher and the regulator.

incoming

BidRequest

ACP · openrtb-spec · BidRequest

Arrives from supply. Bidhalo normalises the auction into a typed signal the agents reason over — inventory path, device, audience, time-of-day — and pins a payload_ref id that the audit entry cites back to.

outgoing

BidResponse

ACP · openrtb-spec · BidResponse

Returned to the exchange with the agent-computed clearing price. The full BidResponse — seatbid, bid, price — is stored alongside the ledger entry, so the price the publisher actually paid is replay-eligible.

emitted by Bidhalo

AgentDecision

ACP · bidhalo audit-log · AgentDecision

The Bidhalo-native audit record emitted beside every ACP payload. Carries agent identity (name + version), kind, severity, the delta applied, the source input, and the reasoning that produced it.

emitted by Bidhalo

PolicyViolation

ACP · policy-channel · PolicyViolation

Raised inline when the IVT detector or the AdCP policy channel flags a supply path. Recorded as a severity: flag decision with the offending supply pool, the rule that fired, and the action taken (usually bids withdrawn, awaiting human re-entry).

Field mapping

What Bidhalo records alongside each ACP payload.

Every ACP message Bidhalo handles is paired with a typed ledger entry. The table below is the field-by-field map — the Bidhalo type the contract ships in src/lib/contracts/decision.ts, and the source of the value.

FieldBidhalo typeSourceNotes
idstringBidhalo audit logStrongly-typed cuid; primary key of the ledger entry.
tsISO-8601 stringBidhalo audit logUTC moment the record was sealed — signed at write, replayable from.
agent.namestringBidhalo agentThe agent that authored the decision (e.g. "Rebalance Agent", "IVT Defense Agent").
agent.versionstringBidhalo agentPinned at write — so a replay from any timestamp reconstructs the exact reasoning.
severityok | watch | flagBidhalo agentRoutes alerts; "flag" decisions require human sign-off before bids resume.
kindBID_REBALANCE | PACING_SHIFT | IVT_QUIT | BUDGET_CAPBidhalo agentThe class of decision — drives both audit grouping and downstream alerting.
delta.kindbid | budgetBidhalo agentWhether the move touched a bid floor or a budget envelope.
delta.directionraise | lower | holdBidhalo agentThe direction the agent moved the delta against its CPM / pacing ceiling.
delta.magnitudestringBidhalo agentHuman-readable (e.g. "+6.4%", "$42.8k cap", "Bid withdrawn") — surfaces in the publisher ops view.
reasoningstringBidhalo agentThe natural-language reasoning chain — what the agent saw and why it acted.
payload_refstringACPPointer back to the BidRequest / BidResponse / PolicyViolation being recorded. Joins audit-log to protocol traffic.

Sample payload

An ACP bid exchange, annotated with the decision-log entry that records it.

The top block is the protocol traffic as it crosses the Bidhalo boundary. The bottom block is the Bidhalo decision that records the agent's reasoning. Annotations sit on the right of the Bidhalo-only lines.

ACP payload · BidRequestincoming from supply
{
  "id": "req-0x9A-2c8f",          // payload_ref — joins BidRequest to the ledger row below
  "imp": [{
    "id": "1",
    "banner": { "w": 1920, "h": 1080 },
    "bidfloor": 4.20,
    "inventory": "0x9A · CTV pre-roll"
  }],
  "site": { "domain": "news.example", "cat": ["IAB12"] },
  "device": {
    "devicetype": 3,              // CTV
    "geo": { "country": "USA" }
  },
  "user": { "id": "..." },
  "tmax": 120,
  "at": 2                        // second-price auction
}
ACP payload · BidResponseoutgoing to exchange
{
  "id": "req-0x9A-2c8f",
  "seatbid": [{
    "bid": [{
      "id": "bid-7Q2",
      "impid": "1",
      "price": 4.467,             // 4.20 × 1.064 — the agent's raised clearing price
      "adid": "creative-42",
      "adm": "<vast>...</vast>"
    }]
  }]
}
Bidhalo decision-log entryrecorded at write · tamper-evident
{
  "id": "log-001",
  "ts": "2026-08-26T14:02:11-07:00",
  "agent": { "name": "Rebalance Agent", "version": "3.4.1" },
  "severity": "ok",
  "kind": "BID_REBALANCE",
  "delta": {
    "kind": "bid",
    "direction": "raise",
    "magnitude": "+6.4%",
    "note": "Raised the floor bid to hold win-rate after an IVT spike thinned clean supply."
  },
  "reasoning":
    "A burst of invalid traffic on inventory 0x9A dropped clean-impression 
Bidhalo-only annotation lines— every field above is a typed contract entry, not a free-text comment.
    volume 18% below the trailing 15-minute baseline. Rather 
    than let win-rate degrade on the remaining clean supply, the
    agent raised the floor bid 6.4% — bounded by the campaign
    CPM ceiling — to hold delivery pacing while the IVT filter
    cleared the bad traffic. The bid reverted automatically once
    volume normalized.",
  "payload_ref": "req-0x9A-2c8f"
}

Wire Bidhalo into an AdCP tenanted account

See the protocol layer running against your inventory.

We'll replay a sample auction, walk through every ACP message Bidhalo emits, and show the tamper-evident ledger entry that records it. Pick a plan when you're ready.