# Minimal OpenRTB 2.6 bidder in Rust

The code from the tutorial at https://rtblint.org/learn/build-a-bidder-rust/.

It accepts OpenRTB 2.6 bid requests on `POST /bid`, validates them with the
[rtblint-core](https://crates.io/crates/rtblint-core) crate, bids on the first
banner or video impression it has a creative for, and logs win notices on
`/win`. It behaves like the Node.js bidder at
https://rtblint.org/learn/build-a-bidder-node/.

## Requirements

Rust 1.89 or later with the dependency versions current in November 2026
(uuid 1.29 sets that minimum; the code itself needs 1.80 for
`std::sync::LazyLock`). Tested with Rust 1.97.1.

## Layout

```
Cargo.toml
src/main.rs
```

## Run

```sh
cargo run --release
```

The server listens on port 8080. Set `PORT` to change it and `PUBLIC_URL` to
the address exchanges reach you on, because it is written into `nurl`.

## Test

```sh
cargo test
```

The unit test builds a bid for a small request and validates it against that
request with `rtblint_core::validate_bid_response_against_request`.

## Send a request

Use the sample request from the Node.js tutorial
(https://rtblint.org/downloads/bidder-node/sample-request.json):

```sh
curl -s -X POST http://localhost:8080/bid \
  -H 'content-type: application/json' \
  --data @sample-request.json -o response.json -w '%{http_code}\n'
```

Status codes:

- `200` with a BidResponse: a bid.
- `200` with `{"id": "...", "nbr": 2}`: the request failed validation.
- `204` with no body: no bid (no matching imp, floor above the cap, blocked
  advertiser domain, currency other than USD, or the tmax budget ran out).
- `400` with no body: the body was not UTF-8 JSON or was larger than 256 KB.

## Scope

This is a starting point for learning the protocol, not a production bidder.
