> ## Documentation Index
> Fetch the complete documentation index at: https://agenticadvertisingorg-snap-format-preview-links.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Property Governance Specification

> Formal specification for AdCP property governance — property models, feature evaluation, list management, and delivery validation.

**Status**: Stable (shipped in AdCP 3.0 as the `property-lists` specialism under the `governance` protocol)
**Last Updated**: April 2026

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119).

## Abstract

The Property Protocol defines a standard Model Context Protocol (MCP) and Agent-to-Agent (A2A) interface for property identity, authorization, data provision, and selection. This protocol enables publishers to declare properties and authorized agents, data providers to offer property intelligence, and buyers to select compliant property sets.

## Overview

The Property Protocol addresses four distinct concerns:

| Concern                 | Question                               | Owner          | Mechanism                                     |
| ----------------------- | -------------------------------------- | -------------- | --------------------------------------------- |
| **Property Identity**   | What properties exist?                 | Publishers     | `adagents.json` properties array              |
| **Sales Authorization** | Who can sell this property?            | Publishers     | `adagents.json` authorized\_agents            |
| **Property Data**       | What do we know about this property?   | Data providers | Governance agents via `get_adcp_capabilities` |
| **Property Selection**  | Which properties meet my requirements? | Buyers         | Property lists with filters                   |

The first two are **publisher-side declarations** via adagents.json. The last two are **buyer-side operations** that consume property data from governance agents.

### Property Data and Selection

Property data and selection use a **stateful** model:

* **Feature discovery**: Agents advertise what they can evaluate via `get_adcp_capabilities`
* **Property list management**: CRUD operations for managed property lists with filters
* **Brand references**: Let agents automatically apply rules based on brand identity
* **Webhook notifications**: Real-time updates when resolved lists change
* **Marketplace architecture**: Multiple specialized agents as subscription services

All evaluation (scoring, filtering, discovery) happens implicitly when property lists are resolved via `get_property_list`.

## Core Concepts

### Request Roles and Relationships

Every governance request involves two key roles:

#### Orchestrator (Buyer Agent)

The platform or system making the API request to the governance agent. In AdCP documentation, this role is often called a "buyer agent" when operating in the media buying context.

* **Examples**: DSP, trading desk platform, campaign management tool
* **Responsibilities**: Makes API calls, handles authentication, manages the technical interaction
* **Account**: Has technical credentials and API access to the governance agent

#### Account

The billing and policy entity on whose behalf the request is being made, identified via `account` (`account_id` or the `{brand, operator}` natural key):

* **Examples**: Advertiser (Nike), agency (Omnicom), brand team
* **Responsibilities**: Owns the campaign objectives and policy requirements
* **Policies**: May have custom thresholds, blocklists, or compliance requirements

### Property Identification

Properties are identified using the standard AdCP property model:

```json theme={null}
{
  "property_type": "website",
  "name": "Example News",
  "identifiers": [
    { "type": "domain", "value": "example.com" }
  ],
  "supported_channels": ["display", "olv"]
}
```

Property types include: `website`, `mobile_app`, `ctv_app`, `desktop_app`, `dooh`, `podcast`, `radio`, `linear_tv`, `streaming_audio`, `ai_assistant`. Properties may also declare `supported_channels` to indicate which advertising channels their inventory aligns with.

### Property List References

For large property sets, use property list references instead of embedding properties:

```json theme={null}
{
  "property_list_ref": {
    "agent_url": "https://lists.example.com",
    "list_id": "premium_news_sites",
    "auth_token": "eyJhbGciOiJIUzI1NiIs..."
  }
}
```

The receiving agent fetches and caches the list independently, enabling:

* **Scale**: Pass 50,000+ properties without payload bloat
* **Updates**: Lists evolve without changing requests
* **Authorization**: Token controls access to the list

### Governance Agent Types

#### Compliance Agents

Specialized vendors providing property compliance intelligence:

* **Examples**: Data integrity scoring, consent quality measurement
* **Business Model**: Subscription or per-query pricing
* **Methodology**: Published rubrics for transparency

#### Brand Safety Agents

Content classification and risk assessment:

* **Examples**: Content categorization, brand safety scoring
* **Coverage**: May specialize by channel or geography

#### Quality Agents

Performance and fraud measurement:

* **Examples**: Viewability prediction, IVT detection
* **Integration**: May correlate with campaign outcomes

### Scoring and Data Privacy

#### Scores Are Internal

**Critical design principle**: Raw scores are NOT shared with buyers or downstream clients. This prevents data leakage.

Governance agents maintain internal scoring models, but the protocol is designed around **list management**, not score exposure:

* Buyers specify **thresholds** via `feature_requirements` (e.g., `"min_value": 85`)
* Agents return **pass/fail lists** of properties that meet the thresholds
* Raw scores never leave the governance agent

This design prevents:

* Score enumeration attacks (running lists with different thresholds to reverse-engineer scores)
* Competitive intelligence leakage
* Data arbitrage where buyers resell scoring data

#### What Buyers Receive

When calling `get_property_list`, buyers receive a compact list of identifiers (not full property objects) for efficiency:

```json theme={null}
{
  "list_id": "pl_abc123",
  "identifiers": [
    { "type": "domain", "value": "bbc.co.uk" },
    { "type": "domain", "value": "theguardian.com" },
    { "type": "domain", "value": "ft.com" }
  ],
  "total_count": 847
}
```

Properties that pass the threshold are included. Properties that fail are excluded. No scores or property metadata are returned - just the identifiers needed for bid-time lookups.

#### Methodology Discovery

The `get_adcp_capabilities` task returns information about what features an agent evaluates and their methodology, but NOT the underlying scores:

```json theme={null}
{
  "features": [
    {
      "feature_id": "mfa_score",
      "name": "Made For Advertising Score",
      "type": "quantitative",
      "range": { "min": 0, "max": 100 },
      "methodology": "mfa_detection",
      "methodology_version": "v2.1",
      "methodology_url": "https://quality.example.com/methodology"
    }
  ]
}
```

This allows buyers to:

* Understand what an agent measures
* Compare methodologies across agents
* Set appropriate thresholds

But they cannot retrieve the actual scores for individual properties.

## Tasks

### Discovery

#### get\_adcp\_capabilities

Discover what features a governance agent can evaluate.

**Use Cases**:

* Capability discovery: Understand what an agent can evaluate
* Marketplace browsing: Compare features across agents
* Integration planning: Know what filters are available before creating lists

### Property List Management

#### create\_property\_list

Create a new property list with filters and optional brand reference.

**Optional Filters**:

* `countries_all` (string\[]): ISO 3166-1 alpha-2 country codes — property must have data for ALL. Omit for global lists.
* `channels_any` (string\[]): Advertising channels — property must support ANY. Omit for all-channel lists.

**Base Properties**: An array of property sources to evaluate. Each entry is a discriminated union with `selection_type` as the discriminator:

* **`publisher_tags`**: `{ "selection_type": "publisher_tags", "publisher_domain": "...", "tags": [...] }` - tags scoped to publisher
* **`publisher_ids`**: `{ "selection_type": "publisher_ids", "publisher_domain": "...", "property_ids": [...] }` - property IDs scoped to publisher
* **`identifiers`**: `{ "selection_type": "identifiers", "identifiers": [...] }` - no publisher context needed
* **Omitted**: Query the agent's entire property database

See the [base-property-source schema](https://adcontextprotocol.org/schemas/v3/property/base-property-source.json) for the full specification.

**Filter Logic** (explicit in field names):

* `countries_all`: Property must have feature data for **ALL** listed countries
* `channels_any`: Property must support **ANY** of the listed channels
* `feature_requirements`: Property must pass **ALL** requirements (AND)

**Use Cases**:

* Define compliant property sets with filters (country, channel, feature thresholds)
* Provide brand reference for automatic rule application
* Register webhook URL for change notifications

#### update\_property\_list

Modify an existing property list.

**Use Cases**:

* Add or remove properties from base list
* Adjust filters based on campaign needs
* Update webhook URL

#### get\_property\_list

Retrieve a property list with resolved properties.

**Use Cases**:

* Get the current list of compliant properties after filters applied
* Cache resolved list for bid-time use
* Retrieve updated list after webhook notification

#### list\_property\_lists

List property lists owned by a given account, or all property lists accessible to the authenticated agent when `account` is omitted.

#### delete\_property\_list

Remove a property list.

### Validation

#### validate\_property\_delivery

Validates delivery records against a property list to determine compliance. Closes the loop between "what I wanted" and "what I got."

Performs two independent validations:

1. **Property compliance**: Is the identifier in the resolved property list?
2. **Supply path authorization**: Was the sales agent authorized to sell that property? (optional, requires `sales_agent_url`)

**Use Cases**:

* Post-campaign validation: Verify impressions landed on compliant properties
* Supply path verification: Confirm sales agents were authorized by publishers
* Real-time monitoring: Check compliance rate during campaign execution
* Audit trails: Generate compliance reports for regulatory or brand safety reviews

**Property Validation Statuses**:

* `compliant`: Identifier is in the resolved property list
* `non_compliant`: Identifier is NOT in the resolved property list
* `not_covered`: Identifier recognized but governance agent has no data for it (e.g., property too new)
* `unidentified`: Identifier type not resolvable by this agent (e.g., detection failed, unsupported type)

**Authorization Validation Statuses** (when `sales_agent_url` provided):

* `authorized`: Sales agent is listed in publisher's adagents.json
* `unauthorized`: Sales agent is NOT in publisher's authorized\_agents list
* `unknown`: Could not fetch or parse adagents.json

**Unverifiable Records**: Both `not_covered` and `unidentified` records should be excluded when calculating compliance rates - you cannot penalize for detection gaps or coverage limitations. The distinction helps identify whether the gap is in the agent's data coverage vs the identifier resolution.

**Response Format**: The response returns raw counts (compliant, non\_compliant, not\_covered, unidentified impressions). Consumers calculate rates as needed. Governance agents may optionally include an `aggregate` field with computed metrics (score, grade, label) - the format and meaning are agent-specific.

## Typical Flows

### Property List Flow

Property lists enable buyers to define and manage compliant property sets:

1. **Create property list**: Buyer defines list on governance agent with filters
2. **Resolve and iterate**: Buyer calls `get_property_list` to see resolved properties
3. **Share list reference**: Buyer provides `list_id` to orchestrator/seller
4. **Cache locally**: Orchestrator/seller fetches and caches resolved properties
5. **Use at bid time**: Orchestrator/seller uses local cache (no governance agent calls)
6. **Refresh periodically**: Re-fetch based on `cache_valid_until` (typically 1-24 hours)

**Important**: Governance agents are NOT in the real-time bid path. All bid-time decisions use locally cached property sets.

### Webhook and Caching Pattern

Webhooks provide **notification** that a property list has changed. The webhook payload contains a summary of changes, but you must call `get_property_list` to retrieve the actual updated properties.

```
┌─────────────────────────────────────────────────────────────────┐
│                     Webhook Flow                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. Governance agent re-evaluates properties (background)       │
│  2. Webhook fires with change summary (added/removed counts)    │
│  3. Recipient calls get_property_list to fetch updated list     │
│  4. Recipient updates local cache                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

**Best Practices for Downstream Consumers**:

Consumers of property lists (orchestrators, sellers, buyer agents) should implement **at least one** of these patterns:

1. **Webhook-driven updates** (recommended): Register a webhook URL when creating the property list. Re-fetch via `get_property_list` when notified of changes.

2. **Polling with cache hints**: Use `cache_valid_until` from `get_property_list` responses to schedule periodic re-fetches. Typical validity periods are 1-24 hours.

3. **Hybrid approach**: Use webhooks for immediate updates, with polling as a fallback safety net.

**Cache Expiry Guidance**:

Every `get_property_list` response includes:

* `resolved_at`: When the list was evaluated
* `cache_valid_until`: When consumers should consider the cache stale

```json theme={null}
{
  "resolved_at": "2026-01-04T10:00:00Z",
  "cache_valid_until": "2026-01-04T22:00:00Z"
}
```

Consumers MUST NOT use cached data beyond `cache_valid_until` without re-fetching.

### Property Discovery Flow

1. **Define filters**: Specify country, channel, quality thresholds when creating property list
2. **Resolve list**: Call `get_property_list` with `resolve=true` to get matching properties
3. **Review candidates**: Evaluate returned properties for fit
4. **Add to campaign**: Include property list reference in media buy

## Response Structure

All AdCP Governance responses follow a consistent structure:

### Core Response Fields

* **message**: Human-readable summary of the operation result
* **context\_id**: Session continuity identifier for follow-up requests
* **data**: Task-specific payload (varies by task)

### Protocol Transport

* **MCP**: Returns complete response as flat JSON object
* **A2A**: Returns as structured artifacts with message in text part, data in data part
* **Data Consistency**: Both protocols contain identical AdCP data structures

## Error Handling

### Error Codes

* `REFERENCE_NOT_FOUND`: Referenced property, policy, or property list does not exist or is not accessible by the caller. Returned uniformly for both "does not exist" and "exists but unauthorized" — see [Uniform response for inaccessible references](/docs/building/implementation/error-handling#standard-error-codes).
* `PROPERTY_NOT_MONITORED`: Governance agent doesn't cover this property
* `METHODOLOGY_NOT_SUPPORTED`: Requested methodology version unavailable
* `PARTIAL_RESULTS`: Some properties couldn't be evaluated

### Partial Success

For bulk operations, the response may include partial results:

```json theme={null}
{
  "message": "Evaluated 847 of 850 properties. 3 properties not in coverage.",
  "context_id": "ctx-gov-123",
  "scores": [...],
  "errors": [
    {
      "code": "PROPERTY_NOT_MONITORED",
      "property": { "identifiers": [{ "type": "domain", "value": "unknown.com" }] },
      "message": "Property not in monitoring coverage"
    }
  ]
}
```

## Implementation Notes

### Caching Architecture

Governance decisions are highly cacheable:

#### Orchestrator-Side Caching

* **Score cache**: Store scores with TTL from `valid_until` field
* **Decision cache**: Pre-compute pass/fail for campaigns
* **List cache**: Cache property lists from `property_list_ref`

#### Agent-Side Caching

* **Profile cache**: Maintain pre-computed property profiles
* **Methodology cache**: Cache scoring algorithm results

### Performance Requirements

| Operation                     | Target Latency |
| ----------------------------- | -------------- |
| Single property score         | \< 100ms       |
| Bulk scoring (100 properties) | \< 2s          |
| Filter decision (cached)      | \< 5ms         |
| Property discovery            | \< 5s          |

### Multi-Agent Strategies

Orchestrators may consult multiple governance agents:

1. **Primary + Validation**: Use primary agent, validate with secondary
2. **Specialization**: Route by property type to specialist agents
3. **Consensus**: Require multiple agents to agree
4. **Competitive**: Track agent accuracy, weight by performance

## Agent Discovery

There are two complementary discovery mechanisms:

### Publisher-Side Discovery via adagents.json

Publishers declare which governance agents have data about their properties using the `property_features` field in `adagents.json`:

```json theme={null}
{
  "property_features": [
    {
      "url": "https://api.sustainability-vendor.example",
      "name": "Sustainability Vendor",
      "features": ["carbon_score", "green_media_certified"],
      "publisher_id": "pub_12345"
    },
    {
      "url": "https://api.quality-vendor.example",
      "name": "Quality Vendor",
      "features": ["mfa_score", "ad_density", "page_speed"]
    }
  ]
}
```

This solves the discovery problem: buyers don't need to query every possible governance agent. Instead, they read `property_features` from the publisher's adagents.json to find which agents have relevant data.

See the [adagents.json Tech Spec](/docs/governance/property/adagents#governance-agent-discovery) for the complete discovery workflow.

### Agent-Side Discovery via agent-card.json

Governance agents expose capabilities via `.well-known/agent-card.json`:

```json theme={null}
{
  "name": "Example Compliance Provider",
  "url": "https://compliance.example.com",
  "capabilities": {
    "tasks": [
      "get_adcp_capabilities",
      "create_property_list",
      "get_property_list",
      "update_property_list",
      "delete_property_list",
      "list_property_lists",
      "validate_property_delivery"
    ],
    "protocols": ["MCP", "A2A"],
    "schema_version": "v1"
  },
  "methodology": {
    "documentation_url": "https://compliance.example.com/methodology",
    "scoring_frameworks": ["data_integrity_index", "brand_safety_score"],
    "coverage": {
      "property_types": ["website", "mobile_app", "ctv_app"],
      "jurisdictions": ["GDPR", "CCPA", "COPPA"]
    }
  }
}
```

### Detailed Capability Discovery

Use `get_adcp_capabilities` for detailed capability discovery:

```json theme={null}
{
  "tool": "get_adcp_capabilities",
  "arguments": {}
}
```

Returns the specific features the agent can evaluate (mfa\_score, carbon\_score, brand\_risk, etc.).

## Marketplace Architecture

The Property Protocol enables a marketplace of specialized data agents:

```
┌─────────────────────────────────────────────────────────────────────────┐
│                         SELLER AGENT (DSP/SSP)                          │
│  "Give me the compliant property list for this campaign"                │
└───────────────────────────────┬─────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                    BUYER AGENT (implements Property Protocol)           │
│  - Exposes: get_adcp_capabilities, get_property_list, webhooks         │
│  - Source of truth for final compliant list                             │
│  - Intersects results from specialized agents                           │
└───────────────────────────┬─────────────────────────────────────────────┘
                            │
        ┌───────────────────┼───────────────────┐
        ▼                   ▼                   ▼
┌───────────────┐   ┌───────────────┐   ┌───────────────┐
│ Quality Agent │   │ Sustainability│   │ Suitability   │
│               │   │    Agent      │   │    Agent      │
├───────────────┤   ├───────────────┤   ├───────────────┤
│ Features:     │   │ Features:     │   │ Features:     │
│ mfa_score     │   │ carbon_score  │   │ content_cat   │
│ ad_density    │   │ climate_risk  │   │ brand_risk    │
│ page_speed    │   │ green_media   │   │ sentiment     │
├───────────────┤   ├───────────────┤   ├───────────────┤
│ Subscription  │   │ Subscription  │   │ Subscription  │
└───────────────┘   └───────────────┘   └───────────────┘
```

### Key Principles

1. **Buyer agent is source of truth**: The buyer agent aggregates data from multiple specialized governance agents
2. **Seller sees one interface**: Sellers interact only with the buyer agent using standard Property Protocol
3. **Subscription model**: Each specialized agent is a paid service with its own features and coverage
4. **Webhook-driven updates**: Specialized agents notify the buyer agent when property evaluations change

### Multi-Agent Orchestration

A buyer agent can distribute a master property list to multiple specialized agents:

```python theme={null}
# Buyer agent creates variants on each specialized agent
consent_list = consent_agent.create_property_list(
    name="Q1 Campaign - Consent",
    base_properties=master_list,
    brand=brand
)
# Configure webhook for updates
consent_agent.update_property_list(
    list_id=consent_list.list_id,
    webhook_url="https://buyer.example.com/webhooks/consent"
)

suitability_list = suitability_agent.create_property_list(
    name="Q1 Campaign - Sustainability",
    base_properties=master_list,
    brand=brand
)
suitability_agent.update_property_list(
    list_id=suitability_list.list_id,
    webhook_url="https://buyer.example.com/webhooks/suitability"
)

# Buyer agent intersects filtered results
def on_list_changed(event):
    consent_props = consent_agent.get_property_list(consent_list.list_id, resolve=True)
    suitability_props = suitability_agent.get_property_list(suitability_list.list_id, resolve=True)

    # Intersection = properties that pass ALL governance agents
    compliant_props = intersect(consent_props, suitability_props)

    # Update buyer agent's exposed list
    update_compliant_list(compliant_props)
```

### Brand

Instead of specifying complex filters, buyers provide a brand reference:

```json theme={null}
{
  "brand": {
    "domain": "toybrand.com"
  }
}
```

Each governance agent resolves the brand identity and applies rules according to their domain expertise:

* **Consent agent**: Applies COPPA requirements for children's brands
* **Brand safety agent**: Filters to appropriate content, excludes violence/adult
* **Sustainability agent**: Applies any green media requirements

The buyer doesn't need to know the specific rules - they declare who they are, and agents figure out what applies.

## Integration with Media Buy Protocol

### Property Lists in Media Buys

The Media Buy Protocol accepts property list references:

```json theme={null}
{
  "task": "create_media_buy",
  "arguments": {
    "packages": [{
      "property_list_ref": {
        "agent_url": "https://governance.example.com",
        "list_id": "approved_q1_campaign",
        "auth_token": "..."
      }
    }]
  }
}
```

### Policy Compliance

Media buys can reference governance policies via property list references:

```json theme={null}
{
  "compliance_requirements": {
    "property_list_ref": {
      "agent_url": "https://compliance.example.com",
      "list_id": "pl_q1_compliant",
      "auth_token": "eyJhbGciOiJIUzI1NiIs..."
    }
  }
}
```

## Best Practices

1. **Cache aggressively**: Property scores change slowly; cache for hours/days
2. **Bulk where possible**: Use batch operations for planning, not per-property calls
3. **Pre-compute decisions**: Build pass/fail lookups before bid-time
4. **Monitor coverage**: Track which properties agents don't cover
5. **Log methodology versions**: For audit trails, record which scoring version was used
6. **Handle partial results**: Not all properties will be scorable; plan for gaps

## Next Steps

* See the [adagents.json Tech Spec](/docs/governance/property/adagents) for property declaration and authorization
* See the [get\_adcp\_capabilities task reference](/docs/protocol/get_adcp_capabilities) for capability discovery
* See the [Property List Management](/docs/governance/property/tasks/property_lists) for CRUD operations and webhooks
* See the [validate\_property\_delivery task reference](/docs/governance/property/tasks/validate_property_delivery) for post-campaign compliance validation
