Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/line-item-display.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ reporting:
visibility: registry_gated
required_credentials: [{ type: dsp_seat, scheme: jwt_keypair,
issuer: "dsp-a", id_required: true }]
terms_acceptance_required: true
terms_ref: { url: "https://examplepub.example/legal/io-terms-2026.pdf",
sha256: "<sha256 of the terms document>", version: "2026.1" }

buying_route: PUBLISHER_AD_SERVER
transaction_mechanism: { available: ["PROGRAMMATIC_GUARANTEED", "PREFERRED_DEAL"],
Expand Down
5 changes: 5 additions & 0 deletions spec/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ issue that caused it, so the comment record and the spec history line up.

## [Unreleased]

- § 5.8, § 5.10, § 7 — `terms_ref` for the exact terms accepted at assent,
`agreement_ref` for the agreement a line item is priced under, and `io` and
`agreement` roles on `external_references[]`. Breaking
([#27](https://github.com/IABTechLab/OpenProposal/issues/27)).

## [3.0-draft-1] — 2026-09-22

Initial draft published for public comment. Ported from the working-group
Expand Down
26 changes: 22 additions & 4 deletions spec/openproposal-3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@ Transitions: `none` → `requested` → `held` → (`expired` | `released` |
| `required_credentials[]` | Array[Object] | seller-set | `{ type: iab_registry \| dsp_seat \| custom, scheme: api_key \| oauth2_client_credentials \| jwt_keypair \| oidc_federated \| none, issuer, id_required }` |
| `eligible_bidders[]` | Array[String] | seller-set | Permitted seat or buyer ids |
| `terms_acceptance_required` | Boolean | seller-set | Whether legal terms must be accepted before assent |
| `terms_ref` | Object | seller-set | OPTIONAL; REQUIRED when `terms_acceptance_required` is `true`. `{ url, sha256, version }`: the legal terms or IO template the buyer accepts at assent. Hash-pinned, so assent (§ 4.1) binds to an exact document |

`terms_ref` MUST be hash-pinned and frozen at `agreed`.

### 5.9 Execution

Expand All @@ -346,11 +349,16 @@ Transitions: `none` → `requested` → `held` → (`expired` | `released` |

| Field | Type | Mutability | Description |
| :--- | :--- | :--- | :--- |
| `external_references[]` | Array[Object] | derived | `{ system, namespace, id, role }`. Replaces platform-specific key names. A buyer-owned reference such as a Prisma `io_id` is supplied |
| `external_references[]` | Array[Object] | derived | `{ system, namespace, id, role }`. Replaces platform-specific key names. A buyer-owned reference such as a Prisma `io_id` is supplied. Documented `role` values: `io`, an IO id generated by an order management system and carried back on the line item; `agreement`, a buyer-held agreement id |
| `agreement_ref` | Object | seller-set | OPTIONAL. Reference to a master or annual agreement the line item is priced under: `{ agreement_id, parties[], type: upfront \| annual \| master_services \| other, valid_from, valid_until }`, where `parties[]` names the seller by its `seller_id` and the buyer by the id it holds in `eligible_bidders[]` (§ 5.8). An informative pointer; the agreement itself is outside this specification. A buyer-held agreement id travels as an `external_references[]` entry with `role: agreement` |
| `correlation_id` | String | derived | One identity for this line item's commitment, carried across every system it touches |
| `billing` | Object | seller-set | `{ supplier_id, billing_supplier_id, payment_terms, invoicing_party }`. Who delivers is not always who invoices |
| `supported_order_systems[]` | Array[String] | seller-set | Declared up front so the agent knows it will reconcile |

This specification does not define IO generation. IO creation is a connector
concern. OpenProposal supplies the agreed record, `terms_ref` and
`correlation_id` a connector needs.

---

## 6. Examples
Expand Down Expand Up @@ -396,6 +404,14 @@ See [`examples/line-item-audio.yaml`](../examples/line-item-audio.yaml).
satisfaction rather than negotiation. Only genuinely out-of-envelope asks
require the counterparty to respond.

**Relationships, agreements and IOs (non-normative).** Buyer–seller
relationships are expressed as issued proposals (`visibility: named`,
`eligible_bidders[]` set to that buyer, with the negotiated `pricing[]`) plus
the buyer agent's business rules. "Preferred partner" weighting is a buyer-side
ranking rule, not part of this specification. `agreement_ref` and `terms_ref`
(§ 5.10, § 5.8) point at the agreement and terms a line item is executed under;
IO generation happens through connectors.

---

## 8. Open questions
Expand Down Expand Up @@ -494,13 +510,15 @@ body is normative.**
| `required_credentials[]` | 5.8 Transaction eligibility | Array[Object] | seller-set |
| `eligible_bidders[]` | 5.8 Transaction eligibility | Array[String] | seller-set |
| `terms_acceptance_required` | 5.8 Transaction eligibility | Boolean | seller-set |
| `terms_ref` | 5.8 Transaction eligibility | Object | seller-set |
| `buying_route` | 5.9 Execution | Enum | seller-set |
| `transaction_mechanism` | 5.9 Execution | Object | selectable |
| `serving_mode` | 5.9 Execution | Enum | seller-set |
| `deal_id_issuance` | 5.9 Execution | String | derived |
| `buyer_requirements` | 5.9 Execution | Object | mixed |
| `serving_platform` | 5.9 Execution | String | seller-set |
| `external_references[]` | 5.10 External references and settlement | Array[Object] | derived |
| `agreement_ref` | 5.10 External references and settlement | Object | seller-set |
| `correlation_id` | 5.10 External references and settlement | String | derived |
| `billing` | 5.10 External references and settlement | Object | seller-set |
| `supported_order_systems[]` | 5.10 External references and settlement | Array[String] | seller-set |
Expand All @@ -512,7 +530,7 @@ body is normative.**
| Marker | Count | Meaning | Fields |
| :--- | :--- | :--- | :--- |
| immutable | 6 | Set once at creation. Neither party may change it. | `proposal_id`, `seller_id`, `seller_name`, `type`, `line_item_id`, `channel` |
| seller-set | 29 | Seller sets and may revise while `draft` or `published`. | `valid_from` · `valid_until`, `description`, `specifications`, `best_for[]`, `not_suitable_for[]`, `seasonality_notes`, `content_detail`, `specs`, `third_party_tags`, `creative_delivery`, `approval`, `pricing[].cost_method`, `pricing[].gross_rate`, `pricing[].seller_rate`, `pricing[].price_valid_until`, `pricing[].currency`, `pricing[].floor`, `commitment_bounds`, `min_spend`, `creative_policy`, `visibility`, `required_credentials[]`, `eligible_bidders[]`, `terms_acceptance_required`, `buying_route`, `serving_mode`, `serving_platform`, `billing`, `supported_order_systems[]` |
| seller-set | 31 | Seller sets and may revise while `draft` or `published`. | `valid_from` · `valid_until`, `description`, `specifications`, `best_for[]`, `not_suitable_for[]`, `seasonality_notes`, `content_detail`, `specs`, `third_party_tags`, `creative_delivery`, `approval`, `pricing[].cost_method`, `pricing[].gross_rate`, `pricing[].seller_rate`, `pricing[].price_valid_until`, `pricing[].currency`, `pricing[].floor`, `commitment_bounds`, `min_spend`, `creative_policy`, `visibility`, `required_credentials[]`, `eligible_bidders[]`, `terms_acceptance_required`, `terms_ref`, `buying_route`, `serving_mode`, `serving_platform`, `agreement_ref`, `billing`, `supported_order_systems[]` |
| selectable | 12 | Buyer chooses from a declared set. Resolves without assent. | `properties`, `environments`, `audiences`, `activation_route`, `formats`, `production`, `cancellation_policy`, `exclusivity`, `measurement_source`, `shortfall_remedy`, `reporting`, `transaction_mechanism` |
| settable | 5 | Buyer sets a value within declared bounds. Resolves without assent. | `geo`, `device`, `daypart`, `frequency_cap`, `commitment` |
| supplied | 3 | Buyer provides data or an artifact. | `brief_ref`, `buyer_supplied`, `assets[]` |
Expand All @@ -522,8 +540,8 @@ body is normative.**

### What the distribution says

Of 71 fields, **23 are touched by the buyer** — 12 `selectable`, 5 `settable`, 3
`supplied` and 3 `requestable`. The remaining 48 are `seller-set`, `immutable`,
Of 73 fields, **23 are touched by the buyer** — 12 `selectable`, 5 `settable`, 3
`supplied` and 3 `requestable`. The remaining 50 are `seller-set`, `immutable`,
`derived` or `mixed`.

Only the 3 `requestable` fields require a round trip. Everything else the buyer
Expand Down
Loading