> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pecta.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# RTB bid sanity gate: catch unrealistic bid prices

> Flags bids whose price is unrealistically high relative to the impression floor, catching stale configs, decimal-place bugs, and currency mismatches.

The bid sanity gate compares each bid's `price` against the `bidfloor` declared on the corresponding impression in the request. A bid price that is many multiples of the floor typically signals a misconfigured bidder — a stale price config, a decimal-point shift, or a currency mismatch. Letting such bids through inflates auction clearing prices and corrupts pacing data.

## Usage

```typescript theme={null}
import { createEngine, gates } from "@pecta/core";

const engine = createEngine({
  gates: [
    gates.rtb.tmaxGuard({ bufferMs: 15 }),
    gates.rtb.bidSanity({ maxFloorMultiple: 50 }),
    // ...
  ],
  timeout: 15,
});
```

## Options

<ParamField path="maxFloorMultiple" type="number" default="50">
  The maximum ratio of `bid.price` to `imp.bidfloor` allowed. A bid priced at more than this multiple of the floor fails the gate. Defaults to `50`. Must be a positive number — passing zero or a negative value throws at construction time.
</ParamField>

<ParamField path="maxPrice" type="number" default="Infinity">
  A hard upper bound on bid price regardless of the floor. Useful when you want to cap absolute values in addition to the floor-relative check. Defaults to `Infinity` (no hard cap).
</ParamField>

<ParamField path="name" type="string" default="rtb.bid-sanity">
  Override the gate's name in evaluation results and telemetry.
</ParamField>

## What the gate checks

For every bid in `seatbid[].bid[]`, the gate validates:

1. **Missing price** — `bid.price` is absent or not a finite number → fails with `"bid missing price"`
2. **Negative price** — `bid.price < 0` → fails with `"bid price is negative"`
3. **Hard cap exceeded** — `bid.price > maxPrice` → fails with the price and cap value
4. **Floor ratio exceeded** — `bid.price / imp.bidfloor > maxFloorMultiple` → fails with the computed ratio

The floor is read from `imp[].bidfloor` on the matching impression (matched by `bid.impid`). If the impression has no `bidfloor` set, or if the floor is zero or negative, the ratio check is skipped and only the hard cap applies.

## Example: failing bid

A request declares a floor of `0.50` CPM for impression `imp-001`:

```json theme={null}
{
  "imp": [
    {
      "id": "imp-001",
      "bidfloor": 0.50,
      "bidfloorcur": "USD"
    }
  ]
}
```

A bid agent with a stale config returns a price of `75.00` — 150× the floor:

```json theme={null}
{
  "seatbid": [
    {
      "bid": [
        {
          "id": "bid-1",
          "impid": "imp-001",
          "price": 75.00
        }
      ]
    }
  ]
}
```

The gate computes a ratio of 150× against the 50× limit and returns:

```json theme={null}
{
  "name": "rtb.bid-sanity",
  "passed": false,
  "reason": "bid price is 150.0x the bidfloor (max 50x)",
  "latency_ms": 1
}
```

## Skipping behaviour

The gate returns `passed: true, skipped: true` when the response contains no bids. If a bid's `impid` does not match any impression in the request, the floor check is skipped for that bid (only the hard cap applies).

<Info>
  The `bidfloorcur` field is read from the request impression but is not used in the ratio calculation — all values are compared as raw numbers. Ensure your bidder normalises prices to the same currency as the floor before submitting.
</Info>

<Tip>
  Start with the default `maxFloorMultiple: 50` and tighten it once you have baseline data on your pipeline's normal price-to-floor ratios. Values between 10× and 20× are common in well-tuned production setups.
</Tip>
