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.
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
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
ACP messages
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.
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.
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.
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.
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
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.
| Field | Bidhalo type | Source | Notes |
|---|---|---|---|
| id | string | Bidhalo audit log | Strongly-typed cuid; primary key of the ledger entry. |
| ts | ISO-8601 string | Bidhalo audit log | UTC moment the record was sealed — signed at write, replayable from. |
| agent.name | string | Bidhalo agent | The agent that authored the decision (e.g. "Rebalance Agent", "IVT Defense Agent"). |
| agent.version | string | Bidhalo agent | Pinned at write — so a replay from any timestamp reconstructs the exact reasoning. |
| severity | ok | watch | flag | Bidhalo agent | Routes alerts; "flag" decisions require human sign-off before bids resume. |
| kind | BID_REBALANCE | PACING_SHIFT | IVT_QUIT | BUDGET_CAP | Bidhalo agent | The class of decision — drives both audit grouping and downstream alerting. |
| delta.kind | bid | budget | Bidhalo agent | Whether the move touched a bid floor or a budget envelope. |
| delta.direction | raise | lower | hold | Bidhalo agent | The direction the agent moved the delta against its CPM / pacing ceiling. |
| delta.magnitude | string | Bidhalo agent | Human-readable (e.g. "+6.4%", "$42.8k cap", "Bid withdrawn") — surfaces in the publisher ops view. |
| reasoning | string | Bidhalo agent | The natural-language reasoning chain — what the agent saw and why it acted. |
| payload_ref | string | ACP | Pointer back to the BidRequest / BidResponse / PolicyViolation being recorded. Joins audit-log to protocol traffic. |
Sample payload
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.
{
"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
}{
"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>"
}]
}]
}{
"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 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
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.