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

# Property List Management

> Property list tasks in AdCP create, update, get, list, and delete inclusion and exclusion lists combining static sets with dynamic filters.

**Tasks**: Create, update, get, list, and delete property lists.

Property lists are managed resources that combine static property sets with dynamic filters. When resolved, filters are applied to produce the final property set.

## Architecture: Setup Time, Not Real-Time

Property lists are designed for **setup-time** operations, not real-time bid decisions:

```
┌─────────────────────────────────────────────────────────────────┐
│                     SETUP TIME (Campaign Planning)              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. Buyer creates/updates property list on governance agent     │
│  2. Buyer resolves list to get current properties               │
│  3. Buyer provides list_id to orchestrator/seller               │
│  4. Orchestrator/seller fetches and caches resolved list        │
│  5. Campaign targets only cached compliant properties           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                     BID TIME (Milliseconds)                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  • Orchestrator/seller uses LOCAL cache only                    │
│  • NO calls to governance agent                                 │
│  • Pass/fail from cached property set                           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                     REFRESH (Periodic)                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  • Orchestrator/seller re-fetches list on schedule              │
│  • Frequency based on cache_valid_until                         │
│  • Typically every 1-24 hours                                   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

This enables:

* **Static lists**: Curated sets of approved properties
* **Dynamic lists**: Properties matching criteria (country, channel, score thresholds)
* **Hybrid lists**: Base set modified by filters

## Tasks Overview

| Task                   | Purpose                                | Response Time              |
| ---------------------- | -------------------------------------- | -------------------------- |
| `create_property_list` | Create a new property list             | \~500ms                    |
| `update_property_list` | Modify an existing list                | \~500ms                    |
| `get_property_list`    | Retrieve list with resolved properties | \~2-5s (depending on size) |
| `list_property_lists`  | List all property lists                | \~500ms                    |
| `delete_property_list` | Delete a property list                 | \~200ms                    |

## Property List Structure

A property list contains:

```json theme={null}
{
  "list_id": "uk_premium_news_q1",
  "name": "UK Premium News Sites Q1 2026",
  "description": "High-quality UK news sites for Q1 campaign",
  "account": { "account_id": "acc_brand_x_direct_01" },
  "base_properties": [
    {
      "selection_type": "publisher_tags",
      "publisher_domain": "raptive.com",
      "tags": ["premium_news", "uk_tier1"]
    }
  ],
  "filters": {
    "countries_all": ["UK"],
    "channels_any": ["display", "video"],
    "feature_requirements": [
      { "feature_id": "mfa_score", "min_value": 90, "max_value": 100 }
    ]
  },
  "brand": {
    "domain": "acmecorp.com"
  },
  "created_at": "2026-01-03T10:00:00Z",
  "updated_at": "2026-01-03T10:00:00Z",
  "property_count": 847
}
```

## Brand

Instead of manually specifying all filters, provide a brand reference and let the governance agent apply appropriate rules based on who you are:

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

The agent resolves the brand identity and applies rules based on its domain expertise:

* A consent agent applies COPPA requirements based on the brand's target audience
* A brand safety agent infers content categories from the brand's industry
* A sustainability agent applies requirements from the brand's profile

The brand reference uses the standard [core/brand-ref](https://adcontextprotocol.org/schemas/v3/core/brand-ref.json) schema. The governance agent resolves the domain to discover the brand's identity via its `brand.json` file.

## Webhooks

Configure webhooks via `update_property_list` to receive notifications when the resolved list changes.

**Important**: Webhooks provide **notification only**. They tell you that the list has changed, but do not stream the updated properties. After receiving a webhook, you must call `get_property_list` to retrieve the updated property set.

### Webhook Flow

```
1. Governance agent re-evaluates properties (periodically or on trigger)
2. Agent detects changes to the resolved property list
3. Webhook fires with change summary (counts, not full list)
4. Recipient calls get_property_list(list_id, resolve=true)
5. Recipient updates local cache with new properties
```

### Webhook Payload

```json theme={null}
{
  "idempotency_key": "plch_01HW9DFQK6NP9R3T5V7X9Z1B3D",
  "event": "property_list_changed",
  "list_id": "uk_premium_news_q1",
  "list_name": "UK Premium News Sites Q1 2026",
  "change_summary": {
    "properties_added": 12,
    "properties_removed": 3,
    "total_properties": 856
  },
  "resolved_at": "2026-01-03T18:00:00Z",
  "cache_valid_until": "2026-01-04T18:00:00Z",
  "signature": "..."
}
```

The webhook payload includes counts but NOT the actual properties. This keeps payloads small and avoids redundant data transfer when recipients may not need the full list immediately.

Recipients MUST verify the `signature` before processing and MUST dedupe by `idempotency_key` so retried deliveries of the same change event are ignored.

### Webhook Use Cases

1. **Buyer agent aggregation**: Receive updates from multiple specialized agents, intersect results
2. **Seller cache invalidation**: Know when to re-fetch the compliant property list
3. **Alerting**: Notify when significant changes occur to compliance status

## Filters

Filters are applied when the list is resolved (via `get_property_list`):

| Filter                 | Type                  | Description                                                                                                                                             |
| ---------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `countries_all`        | string\[]             | ISO 3166-1 alpha-2 country codes (case-insensitive, uppercase recommended) - property must have feature data for ALL. Optional — omit for global lists. |
| `channels_any`         | string\[]             | Advertising channels - property must support ANY. Optional — omit for all-channel lists.                                                                |
| `property_types`       | string\[]             | Property types (website, mobile\_app, ctv\_app, etc.)                                                                                                   |
| `feature_requirements` | FeatureRequirement\[] | Requirements based on agent-provided features                                                                                                           |
| `exclude_identifiers`  | Identifier\[]         | Identifiers to always exclude                                                                                                                           |

### Feature Requirements

Feature requirements reference features discovered via `get_adcp_capabilities`. Each agent exposes different features (mfa\_score, carbon\_score, coppa\_certified, etc.).

For **quantitative** features (scores, ranges):

```json theme={null}
{ "feature_id": "mfa_score", "min_value": 85, "max_value": 100 }
```

For **binary** features (true/false):

```json theme={null}
{ "feature_id": "coppa_certified", "allowed_values": [true] }
```

For **categorical** features (enum values):

```json theme={null}
{ "feature_id": "content_category", "allowed_values": ["news", "sports", "technology"] }
```

### Handling Missing Coverage

When a property doesn't have data for a required feature, you can control the behavior with `if_not_covered`:

```json theme={null}
{
  "feature_id": "mfa_score",
  "min_value": 70,
  "if_not_covered": "include"
}
```

| Value               | Behavior                          | Use Case                                                        |
| ------------------- | --------------------------------- | --------------------------------------------------------------- |
| `exclude` (default) | Property is removed from the list | Strict enforcement - only include properties with verified data |
| `include`           | Property passes this requirement  | Lenient enforcement - don't penalize for coverage gaps          |

When `if_not_covered: "include"` is used, the response includes a `coverage_gaps` field showing which properties were included despite missing data:

```json theme={null}
{
  "identifiers": [...],
  "coverage_gaps": {
    "mfa_score": [
      { "type": "domain", "value": "app.example.com" },
      { "type": "domain", "value": "ctv.example.com" }
    ]
  }
}
```

This transparency helps agencies distinguish between properties that passed a requirement vs. those that couldn't be evaluated.

### Required Filters

Every property list must include at least:

* One country in `countries_all` (ISO 3166-1 alpha-2 code, case-insensitive)
* One channel in `channels_any` (display, video, audio, etc.)

These are required because governance agents need to know which jurisdiction and context to evaluate properties against.

### Filter Logic

The filter field names make the logic explicit:

* **`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).

### Base Properties

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

```json theme={null}
{
  "base_properties": [
    {
      "selection_type": "publisher_tags",
      "publisher_domain": "raptive.com",
      "tags": ["premium_news", "tier1"]
    },
    {
      "selection_type": "publisher_tags",
      "publisher_domain": "mediavine.com",
      "tags": ["lifestyle"]
    },
    {
      "selection_type": "identifiers",
      "identifiers": [
        { "type": "domain", "value": "bbc.co.uk" },
        { "type": "domain", "value": "ft.com" }
      ]
    }
  ]
}
```

Each entry must include `selection_type`:

| selection\_type  | Required Fields                    | Description                                             |
| ---------------- | ---------------------------------- | ------------------------------------------------------- |
| `publisher_tags` | `publisher_domain`, `tags`         | All properties matching these tags within the publisher |
| `publisher_ids`  | `publisher_domain`, `property_ids` | Specific property IDs within the publisher              |
| `identifiers`    | `identifiers`                      | Direct domain/app identifiers (no publisher context)    |

If `base_properties` is omitted, the agent queries its entire property database for properties matching the filters.

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

***

## create\_property\_list

Create a new property list.

### Request

```json theme={null}
{
  "tool": "create_property_list",
  "arguments": {
    "name": "UK Premium News Q1",
    "description": "High-quality UK news sites for Q1 campaign",
    "base_properties": [
      {
        "selection_type": "publisher_tags",
        "publisher_domain": "raptive.com",
        "tags": ["premium_news"]
      }
    ],
    "filters": {
      "countries_all": ["UK"],
      "channels_any": ["display", "video"],
      "feature_requirements": [
        { "feature_id": "mfa_score", "min_value": 85, "max_value": 100 }
      ]
    }
  }
}
```

### Response

```json theme={null}
{
  "message": "Created property list 'UK Premium News Q1'.",
  "context_id": "ctx-gov-list-123",
  "list": {
    "list_id": "pl_abc123",
    "name": "UK Premium News Q1",
    "description": "High-quality UK news sites for Q1 campaign",
    "account": { "account_id": "acc_brand_x_direct_01" },
    "base_properties": [
      {
        "selection_type": "publisher_tags",
        "publisher_domain": "raptive.com",
        "tags": ["premium_news"]
      }
    ],
    "filters": {
      "countries_all": ["UK"],
      "channels_any": ["display", "video"],
      "feature_requirements": [
        { "feature_id": "mfa_score", "min_value": 85, "max_value": 100 }
      ]
    },
    "created_at": "2026-01-03T16:30:00Z",
    "updated_at": "2026-01-03T16:30:00Z",
    "property_count": 847
  },
  "auth_token": "eyJhbGciOiJIUzI1NiIs..."
}
```

### Dynamic List (Filters Only)

Create a list that dynamically queries the governance agent's database (no base\_properties - uses agent's full coverage):

```json theme={null}
{
  "tool": "create_property_list",
  "arguments": {
    "name": "GDPR-Compliant DE Video",
    "description": "All DE properties supporting video with strong consent",
    "filters": {
      "countries_all": ["DE"],
      "channels_any": ["video"],
      "feature_requirements": [
        { "feature_id": "mfa_score", "min_value": 90, "max_value": 100 }
      ]
    }
  }
}
```

***

## update\_property\_list

Modify an existing property list.

### Request - Update Filters

```json theme={null}
{
  "tool": "update_property_list",
  "arguments": {
    "list_id": "pl_abc123",
    "filters": {
      "countries_all": ["UK"],
      "channels_any": ["display", "video"],
      "feature_requirements": [
        { "feature_id": "mfa_score", "min_value": 80, "max_value": 100 }
      ]
    }
  }
}
```

### Request - Replace Base Properties

```json theme={null}
{
  "tool": "update_property_list",
  "arguments": {
    "list_id": "pl_abc123",
    "base_properties": [
      {
        "selection_type": "publisher_tags",
        "publisher_domain": "raptive.com",
        "tags": ["premium_news", "uk_tier1"]
      }
    ]
  }
}
```

### Request - Add Exclusions

```json theme={null}
{
  "tool": "update_property_list",
  "arguments": {
    "list_id": "pl_abc123",
    "filters": {
      "exclude_identifiers": [
        { "type": "domain", "value": "excluded-site.com" }
      ]
    }
  }
}
```

### Response

```json theme={null}
{
  "message": "Updated property list 'UK Premium News Q1'.",
  "context_id": "ctx-gov-list-456",
  "list": {
    "list_id": "pl_abc123",
    "name": "UK Premium News Q1",
    "updated_at": "2026-01-03T17:00:00Z",
    "property_count": 845
  }
}
```

***

## get\_property\_list

Retrieve a property list with optional resolution of filters.

### Request - Get Resolved Properties

```json theme={null}
{
  "tool": "get_property_list",
  "arguments": {
    "list_id": "pl_abc123",
    "resolve": true,
    "pagination": {
      "max_results": 1000
    }
  }
}
```

### Response

The response returns a compact list of **identifiers only** (not full property objects) for efficiency. Only identifiers that pass the feature requirements are included - no scores or metadata.

```json theme={null}
{
  "message": "Retrieved property list 'UK Premium News Q1' with 847 resolved identifiers.",
  "context_id": "ctx-gov-list-789",
  "list_id": "pl_abc123",
  "identifiers": [
    { "type": "domain", "value": "bbc.co.uk" },
    { "type": "domain", "value": "news.sky.com" },
    { "type": "domain", "value": "ft.com" },
    { "type": "domain", "value": "theguardian.com" }
  ],
  "pagination": {
    "has_more": true,
    "cursor": "eyJvZmZzZXQiOjEwMH0=",
    "total_count": 847
  },
  "resolved_at": "2026-01-03T17:15:00Z",
  "cache_valid_until": "2026-01-04T17:15:00Z"
}
```

<Note>
  The `auth_token` is only returned when the list is created via `create_property_list`. Store it securely - you'll need it to share access with sellers.
</Note>

### Request - Get Metadata Only

```json theme={null}
{
  "tool": "get_property_list",
  "arguments": {
    "list_id": "pl_abc123",
    "resolve": false
  }
}
```

### Response (Metadata Only)

```json theme={null}
{
  "message": "Retrieved property list 'UK Premium News Q1' metadata.",
  "context_id": "ctx-gov-list-790",
  "list": {
    "list_id": "pl_abc123",
    "name": "UK Premium News Q1",
    "description": "High-quality UK news sites for Q1 campaign",
    "base_properties": [
      {
        "selection_type": "publisher_tags",
        "publisher_domain": "raptive.com",
        "tags": ["premium_news"]
      }
    ],
    "filters": {
      "countries_all": ["UK"],
      "channels_any": ["display", "video"],
      "feature_requirements": [
        { "feature_id": "mfa_score", "min_value": 85, "max_value": 100 }
      ]
    },
    "created_at": "2026-01-03T16:30:00Z",
    "updated_at": "2026-01-03T17:00:00Z",
    "property_count": 847
  }
}
```

***

## list\_property\_lists

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

### Request

```json theme={null}
{
  "tool": "list_property_lists",
  "arguments": {
    "name_contains": "UK",
    "pagination": {
      "max_results": 50
    }
  }
}
```

### Response

```json theme={null}
{
  "message": "Found 3 property lists matching 'UK'.",
  "context_id": "ctx-gov-list-list-123",
  "lists": [
    {
      "list_id": "pl_abc123",
      "name": "UK Premium News Q1",
      "description": "High-quality UK news sites for Q1 campaign",
      "created_at": "2026-01-03T16:30:00Z",
      "updated_at": "2026-01-03T17:00:00Z",
      "property_count": 847
    },
    {
      "list_id": "pl_def456",
      "name": "UK Sports Sites",
      "description": "UK sports content for sponsorship",
      "created_at": "2026-01-02T10:00:00Z",
      "updated_at": "2026-01-02T10:00:00Z",
      "property_count": 156
    }
  ],
  "pagination": {
    "has_more": false,
    "total_count": 3
  }
}
```

***

## delete\_property\_list

Delete a property list.

### Request

```json theme={null}
{
  "tool": "delete_property_list",
  "arguments": {
    "list_id": "pl_abc123"
  }
}
```

### Response

```json theme={null}
{
  "message": "Deleted property list 'UK Premium News Q1'.",
  "context_id": "ctx-gov-list-del-123",
  "deleted": true,
  "list_id": "pl_abc123"
}
```

***

## Integration with Other Tasks

### Using Lists in score\_properties

Reference a property list instead of passing properties inline:

```json theme={null}
{
  "tool": "score_properties",
  "arguments": {
    "property_list_ref": {
      "agent_url": "https://governance.example.com",
      "list_id": "pl_abc123"
    },
    "scoring_context": {
      "jurisdiction": "GDPR"
    }
  }
}
```

### Using Lists in Media Buys

Pass property lists to media buy creation:

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

***

## Error Codes

| Code                  | Description                                                                                                                                                                                                                                                                                          |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `REFERENCE_NOT_FOUND` | Property list ID doesn't exist, or the caller lacks access. Returned uniformly for both cases — see [Uniform response for inaccessible references](/docs/building/implementation/error-handling#standard-error-codes). Sellers MUST NOT distinguish "exists but unauthorized" from "does not exist." |
| `INVALID_FILTER`      | Filter configuration is invalid                                                                                                                                                                                                                                                                      |
| `LIST_NAME_EXISTS`    | A list with this name already exists                                                                                                                                                                                                                                                                 |

## Caching and Refresh

The `get_property_list` response includes caching guidance:

| Field               | Description                                       |
| ------------------- | ------------------------------------------------- |
| `resolved_at`       | When filters were applied and properties resolved |
| `cache_valid_until` | When consumers should re-fetch the list           |

**Typical flow for orchestrators/sellers:**

```python theme={null}
# Initial setup
response = governance_agent.get_property_list(list_id, resolve=True)
local_cache = build_property_lookup(response.properties)
cache_expiry = response.cache_valid_until

# Periodic refresh (background job)
if now() >= cache_expiry:
    response = governance_agent.get_property_list(list_id, resolve=True)
    local_cache = build_property_lookup(response.properties)
    cache_expiry = response.cache_valid_until

# Bid time (no external calls)
def should_bid(property_domain):
    return property_domain in local_cache
```

## Usage Notes

1. **Setup time only**: Governance agents are not in the real-time bid path; resolve lists during campaign setup
2. **Local caching**: Orchestrators/sellers must cache resolved properties locally for bid-time decisions
3. **Refresh on schedule**: Re-fetch lists based on `cache_valid_until` (typically every 1-24 hours)
4. **Dynamic vs Static**: Use filters-only lists when you want the agent to maintain the property set; use base\_properties when you need explicit control
5. **Pagination**: Large lists may require multiple requests with cursor-based pagination
6. **No score leakage**: Raw scores are kept internal to governance agents; responses contain pass/fail lists, not scores
