OpenProposal 3.0 JSON Schema Unofficial

Decision records · Changes we propose

D-037 How is the ID of a record a party mints written, so that every party compares it the same way?

Proposal Decision 40 on the supporting page of #121. Cited on main and with the open PRs.

What we propose

A UUID in the RFC 9562 string form, which JSON Schema's uuid format checks.

As written

Every ID a party mints, and every reference to one, is any string, as the text types proposal_id and line_item_id: proposal_id, line_item_id, asset_id, correlation_id, idempotency_key, a commitment's proposal_id, requires' line items, and the id of every object option, which included[] and the pricing keys name it by.

The as-written variant takes the option opaque-string. Switch the type map to As written to see it.

Options

  • uuid Chosen

    A UUID in the RFC 9562 string form, which JSON Schema's uuid format checks.

  • opaque-string As written

    Any string the minting party chooses.

Why

The specification types these IDs as strings and says only that each is an identity. A party mints each one, and other parties and systems carry it back, so two independently minted IDs must not collide, and every party must compare an ID the same way. A UUID needs no coordination to be unique, and JSON Schema's uuid format checks its string form, which RFC 9562 reads without regard to case. An ID that another system keeps, such as a DSP seat or a registry entry, stays as that system writes it, and so does proposal_template_id, which links a proposal to the seller's own template and which the text calls opaque to buyers. A reference to a minted record, such as a commitment's proposal_id or requires.all_of[], carries the same identity, so it is a UUID too. With the open PRs, the text says an idempotency_key is opaque and that the seller MUST NOT interpret it. A UUID stays opaque: the schema checks only how it is written, and the seller still compares it for equality and reads nothing from it. The schema departs from the text, which lets the buyer write any string, and from the examples, which write readable names.

What we ask the specification to change

Write every ID a party mints as a UUID (RFC 9562), and every reference to one. That covers proposal_id, line_item_id, asset_id, correlation_id, idempotency_key, and the id of a property or an audience option. A UUID keeps idempotency_key opaque: a seller checks how it is written and compares it, and still reads nothing from it. The examples write readable names such as business-daily-display, which two sellers can mint alike.

The specification lines it rests on

Each line is quoted as the record pins it. Expand an item to read the quote.

main

  • § 4.1, the proposal_id row L183 at 44dfaaf
    proposal_id | String | immutable | Unique identity for the proposal object
  • § 5.1, the line_item_id row L217 at 44dfaaf
    line_item_id | String | immutable | Identity within the proposal
  • § 5.10, the correlation_id row L350 at 44dfaaf
    correlation_id | String | derived | One identity for this line item's commitment, carried across every system it touches
  • § 5.6.1, the commitment.idempotency_key key row L297 at 44dfaaf
    idempotency_key | REQUIRED | Buyer-generated, unique per commitment attempt
  • § 5.4, the assets[] row's description: the inline object L246 at 44dfaaf
    { asset_id, format_ref, url_or_tag, submitted_at, approval_status }
  • § 5.2, the properties row's description: the inline object L225 at 44dfaaf
    { id, name, domains, supported_formats }
  • § 5.3, the audiences row's description: the inline object L233 at 44dfaaf
    { id, name, taxonomy_ref, provenance, addressable_scale }

With the open PRs

  • § 4.1, the proposal_id row L176 on main at 981a74e
    proposal_id | String | immutable | Unique identity for the proposal object
  • § 5.1, the line_item_id row L210 on main at 981a74e
    line_item_id | String | immutable | Identity within the proposal
  • § 5.10, the correlation_id row L343 on main at 981a74e
    correlation_id | String | derived | One identity for this line item's commitment, carried across every system it touches
  • § 5.6.1, the commitment.idempotency_key key row L290 on main at 981a74e
    idempotency_key | REQUIRED | Buyer-generated, unique per commitment attempt
  • § 5.6.1, a sentence L301 in #73
    An idempotency_key is opaque and scoped to one buyer and seller pair.
  • § 5.6.1, a requirement L301 in #73
    The seller MUST NOT interpret it.
  • § 5.6.1, the commitment.proposal_id key row L291 in #73
    proposal_id | REQUIRED | The proposal the commitment is made against
  • § 5.6.3, the requires.all_of[] key row L326 in #70
    all_of[] | Line items that MUST all be in the same commitment
  • § 5.6.3, the requires.any_of[] key row L327 in #70
    any_of[] | Line items of which at least one MUST be in the same commitment
  • § 5.6.3, the requires.min_commitment[] key row's meaning: the inline object L328 in #70
    { line_item_id, basis, amount, currency }
  • § 5.6.3, code block 1 L330-L336 in #70
    requires: all_of: ["business-daily-display", "weather-app-ctv"] any_of: [] min_commitment: - { line_item_id: "business-daily-display", basis: spend, amount: 50000.00, currency: USD }
  • § 5.4, the assets[] row's description: the inline object L239 on main at 981a74e
    { asset_id, format_ref, url_or_tag, submitted_at, approval_status }
  • § 5.2, the properties row's description: the inline object L225 in #17
    { id, name, domains, apps, supported_formats }
  • § 5.3, the audiences row's description: the inline object L226 on main at 981a74e
    { id, name, taxonomy_ref, provenance, addressable_scale }

Examples that follow the text, not this change

ExampleWhereWhyInput
code:5.6.3:1/requires/all_of/0The example follows the text, which states no form for all_of[]: it writes the readable name business-daily-display. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
code:5.6.3:1/requires/all_of/1The example follows the text, which states no form for all_of[]: it writes the readable name weather-app-ctv. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
code:5.6.3:1/requires/min_commitment/0/line_item_idThe example follows the text, which states no form for line_item_id: it writes the readable name business-daily-display. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/line-item-audio.yaml/commitment/idempotency_keyThe example follows the text, which states no form for idempotency_key: it writes the readable name agency-a-camp1-streaming-audio-a7c33e10. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-audio.yaml/commitment/proposal_idThe example follows the text, which states no form for proposal_id: it writes the readable name examplepub-us-q4-2026-omni. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/line-item-audio.yaml/correlation_idThe example follows the text, which types correlation_id as a String: it writes the readable name ep-q4-2026-commitment/streaming-audio. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-audio.yaml/line_item_idThe example follows the text, which types line_item_id as a String: it writes the readable name streaming-audio. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-audio.yaml/production/available/0/idThe example follows the text, which gives a production option no id: the example writes one, the readable name seller_built, as every object option carries. We propose a UUID for every ID a party mints, an object option's id included, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-audio.yaml/production/available/1/idThe example follows the text, which gives a production option no id: the example writes one, the readable name buyer_supplied, as every object option carries. We propose a UUID for every ID a party mints, an object option's id included, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-audio.yaml/production/included/0The example follows the text, which gives a production option no id: the example writes one, the readable name buyer_supplied, and included[] names the option by it. We propose a UUID id for every object option, as for every ID a party mints, so included[] names the option by that UUID.main, open PRs
examples/line-item-audio.yaml/production/pricingThe example follows the text, which gives a production option no id: the example writes one, the readable name seller_built, and the pricing keys name the option by it. We propose a UUID id for every object option, as for every ID a party mints, so the pricing keys name the option by that UUID.main, open PRs
examples/line-item-ctv-bonus.yaml/line_item_idThe example follows the text, which types line_item_id as a String: it writes the readable name weather-app-ctv-bonus. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/line-item-ctv-bonus.yaml/properties/available/0The example follows the text, which states no form for an option's id: it writes the readable name weather-app. We propose a UUID for every ID a party mints, a catalog entry's id included.open PRs
examples/line-item-ctv-bonus.yaml/properties/included/0The example follows the text, which states no form for an option's id: included[] names the property by the readable ID weather-app its available[] gives it. We propose a UUID for every ID a party mints, an option's id included, so included[] names the property by that UUID.open PRs
examples/line-item-ctv-bonus.yaml/requires/all_of/0The example follows the text, which states no form for all_of[]: it writes the readable name business-daily-display. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/line-item-ctv-bonus.yaml/requires/all_of/1The example follows the text, which states no form for all_of[]: it writes the readable name weather-app-ctv. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/line-item-ctv-bonus.yaml/requires/min_commitment/0/line_item_idThe example follows the text, which states no form for line_item_id: it writes the readable name business-daily-display. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/line-item-ctv.yaml/commitment/idempotency_keyThe example follows the text, which states no form for idempotency_key: it writes the readable name agency-a-camp1-weather-app-ctv-3b7e0d52. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-ctv.yaml/commitment/proposal_idThe example follows the text, which states no form for proposal_id: it writes the readable name examplepub-us-q4-2026-omni. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/line-item-ctv.yaml/correlation_idThe example follows the text, which types correlation_id as a String: it writes the readable name ep-q4-2026-commitment/weather-app-ctv. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-ctv.yaml/line_item_idThe example follows the text, which types line_item_id as a String: it writes the readable name weather-app-ctv. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-ctv.yaml/properties/available/0The example follows the text, which states no form for an option's id: it writes the readable name weather-app. We propose a UUID for every ID a party mints, a catalog entry's id included.main, open PRs
examples/line-item-ctv.yaml/properties/included/0The example follows the text, which states no form for an option's id: included[] names the property by the readable ID weather-app its available[] gives it. We propose a UUID for every ID a party mints, an option's id included, so included[] names the property by that UUID.main, open PRs
examples/line-item-display.yaml/audiences/available/1The example follows the text, which states no form for an option's id and lists no terms for provenance: it writes the readable name ep:hnw-investors and the term modeled. We propose a UUID for every ID a party mints, a catalog entry's id included. We also propose namespaced terms in a field until the specification lists its core terms.main, open PRs
examples/line-item-display.yaml/audiences/available/2The example follows the text, which states no form for an option's id and lists no terms for provenance: it writes the readable name ep:cfo-finance-leaders and the term first_party. We propose a UUID for every ID a party mints, a catalog entry's id included. We also propose namespaced terms in a field until the specification lists its core terms.main, open PRs
examples/line-item-display.yaml/audiences/included/0The example follows the text, which states no form for an option's id: included[] writes the readable ID ep:smb-decision-makers. We propose a UUID for every ID a party mints. The entry names the option given as the catalog reference examplepub/audiences/smb-decision-makers@3, though, and that option carries no id, so a UUID alone doesn't name it either. What names an option given as a catalog reference is a point the text leaves open, listed with the examples that disagree with the text.main, open PRs
examples/line-item-display.yaml/audiences/pricingThe example follows the text, which states no form for an option's id: the pricing keys name the audiences by the readable IDs ep:cfo-finance-leaders and ep:hnw-investors their available[] gives them. We propose a UUID for every ID a party mints, an option's id included, so the pricing keys name each audience by that UUID.main, open PRs
examples/line-item-display.yaml/commitment/idempotency_keyThe example follows the text, which states no form for idempotency_key: it writes the readable name agency-a-camp1-business-daily-display-8f42c1a9. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-display.yaml/commitment/proposal_idThe example follows the text, which states no form for proposal_id: it writes the readable name examplepub-us-q4-2026-omni. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/line-item-display.yaml/correlation_idThe example follows the text, which types correlation_id as a String: it writes the readable name ep-q4-2026-commitment/business-daily-display. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-display.yaml/line_item_idThe example follows the text, which types line_item_id as a String: it writes the readable name business-daily-display. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs
examples/line-item-display.yaml/measurement_source/included/0The example follows the text, which gives a measurement source option no id: included[] names the option by its vendor, IAS, which no option of available[] carries as its id. We propose an id on every object option, a UUID as for every ID a party mints, so that included[] names the option by that UUID.main, open PRs
examples/line-item-display.yaml/properties/available/0The example follows the text, which states no form for an option's id: it writes the readable name business-daily. We propose a UUID for every ID a party mints, a catalog entry's id included.main, open PRs
examples/line-item-display.yaml/properties/available/1The example follows the text, which states no form for an option's id: it writes the readable name markets-weekly. We propose a UUID for every ID a party mints, a catalog entry's id included.main, open PRs
examples/line-item-display.yaml/properties/included/0The example follows the text, which states no form for an option's id: included[] names the property by the readable ID business-daily its available[] gives it. We propose a UUID for every ID a party mints, an option's id included, so included[] names the property by that UUID.main, open PRs
examples/line-item-display.yaml/properties/pricingThe example follows the text, which states no form for an option's id: the pricing keys name the property by the readable ID markets-weekly its available[] gives it. We propose a UUID for every ID a party mints, an option's id included, so the pricing keys name the property by that UUID.main, open PRs
examples/line-item-display.yaml/reporting/included/0The example follows the text, which gives a reporting option no id: included[] names the option by its feed_type, aggregate, which no option of available[] carries as its id. We propose an id on every object option, a UUID as for every ID a party mints, so that included[] names the option by that UUID.main, open PRs
examples/line-item-display.yaml/reporting/pricingThe example follows the text, which gives a reporting option no id: the pricing keys name the option by its feed_type, log_level. We propose an id on every object option, a UUID as for every ID a party mints, so that the pricing keys name the option by that UUID.main, open PRs
examples/line-item-rewarded-video.yaml/line_item_idThe example follows the text, which types line_item_id as a String: it writes the readable name puzzle-games-rewarded. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/line-item-rewarded-video.yaml/measurement_source/included/0The example follows the text, which gives a measurement source option no id: included[] names the option by its vendor, IAS, which no option of available[] carries as its id. We propose an id on every object option, a UUID as for every ID a party mints, so that included[] names the option by that UUID.open PRs
examples/line-item-rewarded-video.yaml/properties/available/0The example follows the text, which states no form for an option's id: it writes the readable name puzzle-pack. We propose a UUID for every ID a party mints, a catalog entry's id included.open PRs
examples/line-item-rewarded-video.yaml/properties/included/0The example follows the text, which states no form for an option's id: included[] names the property by the readable ID puzzle-pack its available[] gives it. We propose a UUID for every ID a party mints, an option's id included, so included[] names the property by that UUID.open PRs
examples/manifest.json/proposals/0/proposal_idThe example follows the text, which types proposal_id as a String: it writes the readable name examplepub-us-q4-2026-omni. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.open PRs
examples/proposal.yaml/proposal_idThe example follows the text, which types proposal_id as a String: it writes the readable name examplepub-us-q4-2026-omni. We propose a UUID for every ID a party mints, such as 7c9e6679-7425-40de-944b-e07fc1f90ae7.main, open PRs

What it shapes

main: Uuid, AssetsEntry.approval_status, AssetsEntry.asset_id, AssetsEntry.format_ref, AssetsEntry.submitted_at, AssetsEntry.url_or_tag, AudiencesOption.addressable_scale, AudiencesOption.id, AudiencesOption.name, AudiencesOption.provenance, AudiencesOption.taxonomy_ref, Commitment.idempotency_key, LineItem.correlation_id, LineItem.line_item_id, LineItemSummaryPropertiesOption.name, PropertiesOption.domains, PropertiesOption.id, PropertiesOption.name, PropertiesOption.supported_formats, Proposal.proposal_id

With the open PRs: Uuid, AssetsEntry.approval_status, AssetsEntry.asset_id, AssetsEntry.format_ref, AssetsEntry.submitted_at, AssetsEntry.url_or_tag, AudiencesOption.addressable_scale, AudiencesOption.id, AudiencesOption.name, AudiencesOption.provenance, AudiencesOption.taxonomy_ref, Commitment.idempotency_key, Commitment.proposal_id, LineItem.correlation_id, LineItem.line_item_id, LineItemSummaryPropertiesOption.name, MinCommitmentEntry.amount, MinCommitmentEntry.basis, MinCommitmentEntry.currency, MinCommitmentEntry.line_item_id, PropertiesOption.apps, PropertiesOption.domains, PropertiesOption.id, PropertiesOption.name, PropertiesOption.supported_formats, Proposal.proposal_id, Requires.all_of, Requires.any_of

The record's YAML file