# OpenRTB / DSP Quickstart

The `/openrtb/v2` surface is the authenticated buyer/control plane: discover inventory, forecast, manage deals and creatives, report, and submit OpenRTB 2.6 bid responses. It uses the same centralized platform API key as MCP and reporting.

**Base URL:** `https://api.trillboards.com/openrtb/v2`

## 1. Mint and link one API key

Existing partner owners/admins self-mint at <https://trillboards.com/earner/settings?tab=api> under Partner API. Headless agents can use the existing autonomous registration route instead:

```bash
curl -sS -X POST 'https://api.trillboards.com/v1/partner/agent/register' \
  -H 'Content-Type: application/json' \
  -d '{
    "agent_type": "dsp_agent",
    "name": "Example Buyer Agent",
    "email": "programmatic@example.com",
    "company": "Example Buyer"
  }'
```

The `201` response returns `api_key` once and the exact MCP endpoint
`https://api.trillboards.com/mcp`. Registration is limited to five attempts per
IP per hour. Store the key in a secrets manager and use the canonical header
everywhere:

```http
Authorization: Bearer <platform_api_key>
```

Link that same key to one DSP seat; this grants the DSP capabilities without minting a second credential:

```bash
curl -sS -X POST 'https://api.trillboards.com/openrtb/v2/onboard' \
  -H 'Authorization: Bearer <platform_api_key>' \
  -H 'Content-Type: application/json' \
  -d '{
    "company_name": "Example Buyer",
    "seat_id": "example_buyer",
    "contact_email": "programmatic@example.com"
  }'
```

The response includes `api_key.reused_platform_key: true` and does not echo the secret. Anonymous onboarding still mints a `tb_dsp_*` key only for backwards compatibility. Existing `x-api-key`, `tb_dsp_*`, `tb_prt_*`, and migrated `trb_partner_*` clients continue to work; capabilities, not prefixes, decide access.

## 2. Discover inventory

```bash
curl -sS 'https://api.trillboards.com/openrtb/v2/adslots?format=openrtb&country=US&limit=20' \
  -H 'Authorization: Bearer <platform_api_key>'
```

`format=openrtb` returns ready-to-use `bid_requests` with request and impression IDs. Omit it for the planning-oriented screen summary. Use `/forecast`, `/discover`, `/screens/availability`, and `/deals` with the same header for planning.

## 3. Submit a bid response

`POST /openrtb/v2/bid` accepts an OpenRTB **bid response**, not a supply-side bid request. Match `id` and `impid` to inventory/request IDs received from the buyer flow.

```bash
curl -sS -X POST 'https://api.trillboards.com/openrtb/v2/bid' \
  -H 'Authorization: Bearer <platform_api_key>' \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "request_from_adslots",
    "seatbid": [{
      "seat": "example_buyer",
      "bid": [{
        "id": "bid_001",
        "impid": "imp_65a1b2c3d4e5f6a7b8c9d0e1",
        "price": 4.00,
        "adm": "<VAST version=\"3.0\">...</VAST>",
        "crid": "creative_001",
        "adomain": ["example.com"]
      }]
    }]
  }'
```

New seats start in sandbox. Sandbox status prevents auction injection, but it does not bypass scopes.

| HTTP | Meaning |
|---|---|
| `200` | One or more bids passed validation and were accepted. |
| `204` | No accepted bids; treat as a normal no-bid outcome. |
| `400` | Malformed bid response or missing required field. |
| `401` | Missing, invalid, revoked, or unlinked platform key. |
| `403` | The key lacks the route capability. |
| `415` | `Content-Type` is not `application/json`. |

## Raw exchange bidstream is different

A bilateral supply connection sends OpenRTB bid requests to its configured endpoint:

```text
POST https://api.trillboards.com/openrtb/bidder/<connection_alias>/bid
```

That high-QPS raw bidstream does **not** send the platform API key on every request. Trust comes from the provisioned exchange connection and alias, optional IP allowlist/mTLS/signature, QPS limits, and callback telemetry. Win, impression, and loss use the connection-specific callback URLs returned in each bid.

## Common errors

| `error.code` | HTTP | How to fix |
|---|---:|---|
| `authentication_required` | 401 | Add `Authorization: Bearer <platform_api_key>`. |
| `invalid_api_key` | 401 | Re-check or rotate the self-minted key in the portal. |
| `missing_scope` | 403 | Complete DSP onboarding for that same key or request the missing entitlement. |
| `invalid_json` | 400 | Send valid JSON with `Content-Type: application/json`. |
| `rate_limit_exceeded` | 429 | Honor `Retry-After`; do not retry 204 no-bids. |

## Next steps

- Full DSP reference: <https://api.trillboards.com/docs/dsp>
- Machine-readable OpenAPI: <https://api.trillboards.com/openrtb/v2/openapi.json>
- MCP endpoint: <https://api.trillboards.com/mcp>
- AI-readable contract: <https://api.trillboards.com/llms.txt>
- Error catalog: <https://api.trillboards.com/docs/errors>
