Skip to main content
Discover which publishers a sales agent is authorized to represent. Returns publisher domains only - buyers fetch full property definitions from each publisher’s adagents.json. Response Time: ~2 seconds (database lookup) Purpose:
  • Authorization discovery - which publishers does this agent represent?
  • Single source of truth - property definitions come from publisher’s adagents.json
  • One-time discovery to cache publisher-agent relationships
Request Schema: /schemas/v2/media-buy/list-authorized-properties-request.json Response Schema: /schemas/v2/media-buy/list-authorized-properties-response.json

Request Parameters

ParameterTypeRequiredDescription
publisher_domainsstring[]NoFilter to specific publisher domains (e.g., ["cnn.com", "espn.com"])

Response

FieldDescription
publisher_domainsArray of publisher domains this agent represents
primary_channelsOptional main advertising channels (ctv, display, video, audio, dooh, etc.)
primary_countriesOptional main countries (ISO 3166-1 alpha-2 codes)
portfolio_descriptionOptional markdown description of portfolio and capabilities
last_updatedOptional ISO 8601 timestamp of last publisher list update
See schema for complete field list.

Authorization Workflow

This tool is the first step in understanding what a sales agent represents:
  1. Discovery: Buyer calls list_authorized_properties() to get publisher domains
  2. Fetch Details: Buyer fetches each publisher’s https://publisher.com/.well-known/adagents.json
  3. Validate: Buyer verifies agent is in publisher’s authorized_agents array
  4. Resolve Scope: Buyer resolves authorization scope (property_ids, property_tags, or all properties)
  5. Cache: Buyer caches properties for future product validation

Key Insight: Publishers Own Property Definitions

Unlike traditional SSPs:
  • Publishers define properties in their own adagents.json file
  • Sales agents reference those definitions via domain list
  • Buyers fetch property details from publishers, not agents
  • This ensures single source of truth and prevents property definition drift

Common Scenarios

Discover Agent Portfolio

import { testAgent } from '@adcp/client/testing';
import { ListAuthorizedPropertiesResponseSchema } from '@adcp/client';

// Get all authorized publishers
const result = await testAgent.listAuthorizedProperties({});

if (!result.success) {
  throw new Error(`Request failed: ${result.error}`);
}

// Validate response against schema
const validated = ListAuthorizedPropertiesResponseSchema.parse(result.data);

console.log(`Agent represents ${validated.publisher_domains.length} publishers`);
console.log(`Primary channels: ${validated.primary_channels?.join(', ')}`);
console.log(`Countries: ${validated.primary_countries?.join(', ')}`);

validated.publisher_domains.forEach(domain => {
  console.log(`- ${domain}`);
});

Filter by Publisher

import { testAgent } from '@adcp/client/testing';

// Check if agent represents specific publishers
const result = await testAgent.listAuthorizedProperties({
  publisher_domains: ['cnn.com', 'espn.com']
});

if (result.success && result.data) {
  if (result.data.publisher_domains.length > 0) {
    console.log(`Agent represents ${result.data.publisher_domains.length} of requested publishers`);
    result.data.publisher_domains.forEach(domain => {
      console.log(`✓ ${domain}`);
    });
  } else {
    console.log('Agent does not represent any of the requested publishers');
  }
}

Fetch Publisher Property Definitions

import { testAgent } from '@adcp/client/testing';

// Step 1: Get authorized publishers
const authResult = await testAgent.listAuthorizedProperties({});

if (!authResult.success) {
  throw new Error(`Failed to get authorized properties: ${authResult.error}`);
}

// Step 2: Fetch property definitions from each publisher
const publisherProperties = {};

for (const domain of authResult.data.publisher_domains) {
  const response = await fetch(`https://${domain}/.well-known/adagents.json`);
  if (!response.ok) {
    throw new Error(`Failed to fetch ${domain}: ${response.status}`);
  }
  const adagents = await response.json();

  // Find this agent in publisher's authorized list
  const agentAuth = adagents.authorized_agents.find(
    a => a.url === 'https://test-agent.adcontextprotocol.org/mcp'
  );

  if (agentAuth) {
    // Resolve authorized properties based on scope
    let properties;
    if (agentAuth.property_ids) {
      properties = adagents.properties.filter(
        p => agentAuth.property_ids.includes(p.property_id)
      );
    } else if (agentAuth.property_tags) {
      properties = adagents.properties.filter(
        p => p.tags?.some(tag => agentAuth.property_tags.includes(tag))
      );
    } else {
      properties = adagents.properties; // All properties
    }

    publisherProperties[domain] = properties;
    console.log(`${domain}: ${properties.length} properties authorized`);
  }
}

Check Authorization Scope

import { testAgent } from '@adcp/client/testing';

// Determine what type of agent this is based on portfolio
const result = await testAgent.listAuthorizedProperties({});

if (result.success && result.data) {
  // Check for CTV specialists
  if (result.data.primary_channels?.includes('ctv')) {
    console.log('CTV specialist');
  }

  // Check geographic focus
  if (result.data.primary_countries?.includes('US')) {
    console.log('US market focus');
  }

  // Check for multi-channel capability
  if (result.data.primary_channels && result.data.primary_channels.length > 2) {
    console.log(`Multi-channel agent (${result.data.primary_channels.join(', ')})`);
  }

  // Read portfolio description
  if (result.data.portfolio_description) {
    console.log(`\nAbout: ${result.data.portfolio_description}`);
  }
}

Cache Validation with last_updated

import { testAgent } from '@adcp/client/testing';

// Use last_updated to determine if cache is stale
const result = await testAgent.listAuthorizedProperties({});

if (result.success && result.data) {
  // Example cache from previous fetch (in practice, load from storage)
  const cache = {
    'example-publisher.com': {
      last_updated: '2024-01-15T10:00:00Z',
      properties: []
    }
  };

  for (const domain of result.data.publisher_domains) {
    const cached = cache[domain];

    if (cached && result.data.last_updated) {
      const cachedDate = new Date(cached.last_updated);
      const agentDate = new Date(result.data.last_updated);

      if (cachedDate >= agentDate) {
        console.log(`${domain}: Using cached data (still fresh)`);
        continue;
      }
    }

    console.log(`${domain}: Fetching updated property definitions`);
    // Fetch from publisher's adagents.json...
  }
}

Portfolio Metadata

Optional fields provide high-level portfolio information for quick filtering:

primary_channels

Main advertising channels in portfolio:
  • Values: display, video, dooh, ctv, podcast, retail, etc.
  • See Channels enum
  • Use case: Filter “Do you have DOOH?” before examining properties

primary_countries

Main countries (ISO 3166-1 alpha-2):
  • Where bulk of properties are concentrated
  • Use case: Filter “Do you have US inventory?“

portfolio_description

Markdown description:
  • Inventory types and characteristics
  • Audience profiles
  • Special features or capabilities

Example Portfolios

DOOH Network:
{
  "primary_channels": ["dooh"],
  "primary_countries": ["US", "CA"],
  "portfolio_description": "Premium digital out-of-home across airports and transit. Business traveler focus with proof-of-play."
}
News Publisher:
{
  "primary_channels": ["display", "video", "native"],
  "primary_countries": ["US", "GB", "AU"],
  "portfolio_description": "News and business publisher network. Desktop and mobile web with professional audience."
}

Use Cases

Third-Party Sales Networks

CTV network representing multiple publishers:
  • Returns list of publisher domains
  • Buyers fetch property details from each publisher
  • No duplication of property data across agents

Publisher Direct Sales

Publisher selling own inventory:
  • Returns own domain
  • Buyers fetch from publisher’s adagents.json
  • Consistent with third-party agent flow

Authorization Validation

Buyer validating seller authorization:
  • Discover which publishers agent claims to represent
  • Fetch each publisher’s adagents.json to verify
  • Check agent URL in authorized_agents list
  • Cache validated relationships

Error Handling

Error CodeDescriptionResolution
AUTH_REQUIREDAuthentication neededProvide credentials
INVALID_REQUESTInvalid publisher_domains parameterCheck domain format
NO_PUBLISHERSAgent represents no publishersAgent may be misconfigured

Best Practices

1. Cache Publisher Property Definitions Fetch once and cache - properties rarely change. Use last_updated to detect staleness. 2. Validate Authorization from Publisher Always verify agent is in publisher’s authorized_agents array - don’t trust agent claims alone. 3. Resolve Authorization Scope Check property_ids, property_tags, or assume all properties based on publisher’s authorization entry. 4. Use Portfolio Metadata for Filtering Check primary_channels and primary_countries before fetching detailed properties. 5. Handle Fetch Failures Gracefully Publishers may be temporarily unavailable - cache and retry with backoff.

Next Steps

After discovering authorized properties:
  1. Fetch Properties: GET https://publisher.com/.well-known/adagents.json
  2. Validate Authorization: Find agent in publisher’s authorized_agents array
  3. Cache Properties: Store for use in product validation
  4. Discover Products: Use get_products with cached property context

Learn More