Skip to main content
The adagents.json file provides a standardized way for publishers to declare which sales agents are authorized to sell their advertising inventory. This specification addresses authorization transparency and helps prevent unauthorized reselling of publisher inventory.
AdAgents.json Builder - Validate existing files or create new ones with guided validation

File Location

Publishers must host the adagents.json file at:
https://example.com/.well-known/adagents.json
Following RFC 8615 well-known URI conventions, this location ensures consistent discoverability across publishers.

Basic Structure

The file must be valid JSON with UTF-8 encoding and return HTTP 200 status.
{
  "$schema": "https://adcontextprotocol.org/schemas/v2/adagents.json",
  "contact": {
    "name": "Example Publisher Ad Operations",
    "email": "adops@example.com",
    "domain": "example.com",
    "seller_id": "pub-example-12345",
    "tag_id": "67890"
  },
  "properties": [
    {
      "property_id": "example_site",
      "property_type": "website",
      "name": "Example Site",
      "identifiers": [
        {"type": "domain", "value": "example.com"}
      ]
    }
  ],
  "authorized_agents": [
    {
      "url": "https://agent.example.com",
      "authorized_for": "Official sales agent",
      "authorization_type": "property_ids",
      "property_ids": ["example_site"]
    }
  ],
  "last_updated": "2025-01-10T12:00:00Z"
}

Schema Fields

$schema (optional): JSON Schema reference for validation contact (optional): Contact info for entity managing this file
  • name (required): Name of managing entity (may be publisher or third-party)
  • email (optional): Contact email for questions/issues
  • domain (optional): Primary domain of managing entity
  • seller_id (optional): Seller ID from IAB Tech Lab sellers.json
  • tag_id (optional): TAG Certified Against Fraud ID
properties (optional): Array of properties covered by this file (canonical property definitions) tags (optional): Tag metadata providing human-readable context and enabling efficient grouping authorized_agents (required): Array of authorized sales agents
  • url (required): Agent’s API endpoint URL
  • authorized_for (required): Human-readable authorization description
  • authorization_type (optional): One of property_ids, property_tags, inline_properties, publisher_properties
  • Additional fields: Depends on authorization_type (see patterns below)
last_updated (optional): ISO 8601 timestamp of last modification

URL Reference Pattern

For publishers with complex infrastructure or CDN distribution, adagents.json can reference an authoritative URL instead of containing the full structure inline.

When to Use URL References

  • CDN Distribution: Serve authorization data from a global CDN for better performance
  • Centralized Management: Single source of truth across multiple domains
  • Large Files: When authorization data is too large for inline embedding
  • Dynamic Updates: When authorization needs frequent updates without touching domain files

URL Reference Structure

{
  "$schema": "https://adcontextprotocol.org/schemas/v2/adagents.json",
  "authoritative_location": "https://cdn.example.com/adagents/v2/adagents.json",
  "last_updated": "2025-01-15T10:00:00Z"
}

Requirements

  • HTTPS Required: The authoritative_location must use HTTPS
  • No Nested References: The authoritative file cannot itself be a URL reference (prevents infinite loops)
  • Same Schema: The authoritative file must be a valid inline adagents.json structure
  • Single Hop: Only one level of URL indirection is allowed

Example Use Case: Multi-Domain Publisher

A publisher with multiple domains can maintain one authoritative file: On each domain (https://domain1.com/.well-known/adagents.json, https://domain2.com/.well-known/adagents.json, etc.):
{
  "$schema": "https://adcontextprotocol.org/schemas/v2/adagents.json",
  "authoritative_location": "https://cdn.publisher.com/adagents/v2/adagents.json",
  "last_updated": "2025-01-15T10:00:00Z"
}
Authoritative file (https://cdn.publisher.com/adagents/v2/adagents.json):
{
  "$schema": "https://adcontextprotocol.org/schemas/v2/adagents.json",
  "contact": {
    "name": "Publisher Ad Operations",
    "email": "adops@publisher.com"
  },
  "properties": [
    {
      "property_id": "domain1_site",
      "property_type": "website",
      "name": "Domain 1",
      "identifiers": [{"type": "domain", "value": "domain1.com"}],
      "publisher_domain": "domain1.com"
    },
    {
      "property_id": "domain2_site",
      "property_type": "website",
      "name": "Domain 2",
      "identifiers": [{"type": "domain", "value": "domain2.com"}],
      "publisher_domain": "domain2.com"
    }
  ],
  "authorized_agents": [
    {
      "url": "https://sales-agent.publisher.com",
      "authorized_for": "All publisher properties",
      "authorization_type": "property_ids",
      "property_ids": ["domain1_site", "domain2_site"]
    }
  ],
  "last_updated": "2025-01-15T09:00:00Z"
}

Validation Behavior

When AdCP validators encounter a URL reference:
  1. Fetch Reference: Retrieve the file at /.well-known/adagents.json
  2. Detect Reference: Check for authoritative_location field
  3. Validate URL: Ensure authoritative_location is HTTPS and valid
  4. Fetch Authoritative: Retrieve content from authoritative_location
  5. Prevent Loops: Reject if authoritative file is also a reference
  6. Validate Structure: Validate the authoritative file as normal inline structure

Caching Recommendations

  • Cache reference files for 24 hours minimum
  • Cache authoritative files separately with their own TTL
  • Use last_updated timestamp to detect when cache should be invalidated
  • Implement exponential backoff for failed fetches

Authorization Patterns

AdCP supports four authorization patterns, each optimized for different use cases:

Pattern 1: Property IDs (Direct References)

Best for: Specific, enumerable property lists. Direct and unambiguous. Structure:
{
  "properties": [
    {
      "property_id": "cnn_ctv_app",
      "property_type": "ctv_app",
      "name": "CNN CTV App",
      "identifiers": [
        {"type": "roku_store_id", "value": "12345"}
      ]
    }
  ],
  "authorized_agents": [
    {
      "url": "https://cnn-ctv-agent.com",
      "authorized_for": "CNN CTV properties",
      "authorization_type": "property_ids",
      "property_ids": ["cnn_ctv_app"]
    }
  ]
}
How it works: Agent is authorized for specific properties listed in property_ids array. The properties must be defined in the top-level properties array.

Pattern 2: Property Tags (Efficient Grouping)

Best for: Large networks where one tag can reference hundreds/thousands of properties. Provides grouping efficiency without listing every property ID. Key Insight: Tags are not just “human-readable metadata” - they’re a performance optimization. A publisher with 500 properties can use one tag to authorize all of them, rather than listing 500 property IDs. Structure:
{
  "properties": [
    {
      "property_id": "instagram",
      "property_type": "mobile_app",
      "name": "Instagram",
      "identifiers": [
        {"type": "ios_bundle", "value": "com.burbn.instagram"}
      ],
      "tags": ["meta_network", "social_media"]
    },
    {
      "property_id": "facebook",
      "property_type": "mobile_app",
      "name": "Facebook",
      "identifiers": [
        {"type": "ios_bundle", "value": "com.facebook.Facebook"}
      ],
      "tags": ["meta_network", "social_media"]
    }
  ],
  "tags": {
    "meta_network": {
      "name": "Meta Network",
      "description": "All Meta-owned properties - enables one tag to authorize entire network"
    }
  },
  "authorized_agents": [
    {
      "url": "https://meta-ads.com",
      "authorized_for": "All Meta properties",
      "authorization_type": "property_tags",
      "property_tags": ["meta_network"]
    }
  ]
}
How it works: Agent is authorized for all properties that have ANY of the listed tags. Properties are matched against the tags array in each property definition.

Pattern 3: Inline Properties

Best for: Small, specific property sets without top-level property declarations. Structure:
{
  "authorized_agents": [
    {
      "url": "https://agent.com",
      "authorized_for": "Specific inventory",
      "authorization_type": "inline_properties",
      "properties": [
        {
          "property_type": "website",
          "name": "Example Site",
          "identifiers": [
            {"type": "domain", "value": "example.com"}
          ]
        }
      ]
    }
  ]
}
How it works: Properties are defined directly within the agent authorization entry instead of the top-level properties array. Useful when each agent has unique property definitions.

Pattern 4: Publisher Property References

Best for: Third-party agents representing multiple publishers. Single source of truth for property definitions. Structure:
{
  "contact": {
    "name": "Third-Party CTV Network"
  },
  "authorized_agents": [
    {
      "url": "https://ctv-network.com/api",
      "authorized_for": "CTV inventory from multiple publishers",
      "authorization_type": "publisher_properties",
      "publisher_properties": [
        {
          "publisher_domain": "cnn.com",
          "selection_type": "by_tag",
          "property_tags": ["ctv"]
        },
        {
          "publisher_domain": "espn.com",
          "selection_type": "by_tag",
          "property_tags": ["ctv"]
        }
      ]
    }
  ]
}
How it works: Agent references properties from OTHER publishers’ adagents.json files. The publisher_domain points to the publisher, and selection_type determines how to resolve properties (by_id or by_tag).

Domain Matching Rules

For website properties with domain identifiers, AdCP follows web conventions:

Base Domain (example.com)

Matches domain plus standard web subdomains:
  • example.com
  • www.example.com (standard web)
  • m.example.com (standard mobile)
  • subdomain.example.com (requires explicit authorization)

Specific Subdomain (subdomain.example.com)

Matches only that exact subdomain:
  • subdomain.example.com
  • ❌ All other domains/subdomains

Wildcard (*.example.com)

Matches ALL subdomains but NOT base:
  • ✅ Any subdomain
  • example.com (base domain requires separate authorization)

Real-World Examples

Example 1: Meta Network (Tag-Based)

Large network using tags for grouping efficiency:
{
  "contact": {
    "name": "Meta Advertising Operations",
    "email": "adops@meta.com",
    "domain": "meta.com",
    "seller_id": "pub-meta-12345",
    "tag_id": "12345"
  },
  "properties": [
    {
      "property_type": "mobile_app",
      "name": "Instagram",
      "identifiers": [
        {"type": "ios_bundle", "value": "com.burbn.instagram"},
        {"type": "android_package", "value": "com.instagram.android"}
      ],
      "tags": ["meta_network"],
      "publisher_domain": "instagram.com"
    },
    {
      "property_type": "mobile_app",
      "name": "Facebook",
      "identifiers": [
        {"type": "ios_bundle", "value": "com.facebook.Facebook"},
        {"type": "android_package", "value": "com.facebook.katana"}
      ],
      "tags": ["meta_network"],
      "publisher_domain": "facebook.com"
    },
    {
      "property_type": "mobile_app",
      "name": "WhatsApp",
      "identifiers": [
        {"type": "ios_bundle", "value": "net.whatsapp.WhatsApp"},
        {"type": "android_package", "value": "com.whatsapp"}
      ],
      "tags": ["meta_network"],
      "publisher_domain": "whatsapp.com"
    }
  ],
  "tags": {
    "meta_network": {
      "name": "Meta Network",
      "description": "All Meta-owned properties - one tag authorizes entire network efficiently"
    }
  },
  "authorized_agents": [
    {
      "url": "https://meta-ads.com",
      "authorized_for": "All Meta properties",
      "authorization_type": "property_tags",
      "property_tags": ["meta_network"]
    }
  ]
}
Why this works: One tag (meta_network) authorizes all properties without listing individual property IDs. As Meta adds properties, they just tag them - no need to update agent authorization.

Example 2: CNN (Channel Segmentation)

Different agents for different channels:
{
  "contact": {
    "name": "CNN Advertising Operations",
    "email": "adops@cnn.com",
    "domain": "cnn.com"
  },
  "properties": [
    {
      "property_id": "cnn_ctv_app",
      "property_type": "ctv_app",
      "name": "CNN CTV App",
      "identifiers": [
        {"type": "roku_store_id", "value": "12345"}
      ],
      "tags": ["ctv"]
    },
    {
      "property_id": "cnn_web_us",
      "property_type": "website",
      "name": "CNN.com US",
      "identifiers": [
        {"type": "domain", "value": "cnn.com"}
      ],
      "tags": ["web"]
    }
  ],
  "authorized_agents": [
    {
      "url": "https://cnn-ctv-agent.com",
      "authorized_for": "CNN CTV properties",
      "authorization_type": "property_ids",
      "property_ids": ["cnn_ctv_app"]
    },
    {
      "url": "https://cnn-web-agent.com",
      "authorized_for": "CNN web properties",
      "authorization_type": "property_ids",
      "property_ids": ["cnn_web_us"]
    }
  ]
}

Fetching and Validating

Using the AdAgents.json Builder

The easiest way to validate or create an adagents.json file is using the AdAgents.json Builder web tool. It provides:
  • Domain validation (fetches and checks /.well-known/adagents.json)
  • Structure validation against the JSON schema
  • Agent card endpoint verification (checks if agent URLs respond correctly)
  • Guided file creation with proper formatting

Programmatic Validation

For programmatic validation, use the validation API:
// Validate a domain's adagents.json file
const response = await fetch('https://adcontextprotocol.org/api/adagents/validate', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ domain: 'example.com' })
});

const { success, data } = await response.json();

if (success && data.found) {
  console.log(`Valid: ${data.validation.valid}`);
  console.log(`Agents: ${data.validation.raw_data?.authorized_agents?.length || 0}`);

  // Check for any validation errors
  if (data.validation.errors?.length > 0) {
    console.log('Errors:', data.validation.errors.map(e => e.message));
  }
} else {
  console.log('No adagents.json found at this domain');
}
The validation API fetches https://{domain}/.well-known/adagents.json, validates its structure, follows URL references if present, and optionally checks agent card endpoints.

Using AdCP Client Libraries

The AdCP client libraries provide built-in validation and authorization checking:
import asyncio
from adcp import fetch_adagents, verify_agent_authorization

async def validate_authorization():
    # Fetch and validate adagents.json from a publisher domain
    adagents_data = await fetch_adagents('example-publisher.com')

    # Check if a specific agent is authorized
    is_authorized = verify_agent_authorization(
        adagents_data=adagents_data,
        agent_url='https://our-sales-agent.com',
        property_type='website',
        property_identifiers=[{'type': 'domain', 'value': 'example-publisher.com'}]
    )

    print(f"Agent authorized: {is_authorized}")
    print(f"Total agents: {len(adagents_data.get('authorized_agents', []))}")

asyncio.run(validate_authorization())
The Python library handles validation automatically when fetching - if the adagents.json file is malformed or missing required fields, it raises AdagentsValidationError.

Best Practices

1. Use Appropriate Authorization Pattern

  • Property IDs: Small, enumerable lists (< 20 properties)
  • Property Tags: Large networks (100+ properties)
  • Inline Properties: Simple cases without top-level properties
  • Publisher Properties: Third-party agents representing multiple publishers

2. Cache Files Appropriately

  • Cache for 24 hours minimum
  • Use last_updated timestamp to detect staleness
  • Handle 404 as “no file” (not an error - proceed without validation)
  • Implement retry logic with exponential backoff for network errors

3. Validate Structure

  • Validate against JSON schema before processing
  • Check required fields exist (authorized_agents array)
  • Verify authorization scope matches product claims
  • Cross-reference with seller.json if available

4. Handle Missing Files Gracefully

  • 404 status = No file present (not an authorization failure)
  • Absence of file does not mean agent is unauthorized
  • Use adagents.json as verification, not requirement

Next Steps

After implementing adagents.json validation:
  1. Integrate with Product Discovery: Use get_products to discover inventory
  2. Validate at Purchase: Check authorization before calling create_media_buy
  3. Cache Property Mappings: Store resolved properties for efficient validation
  4. Monitor Authorization: Track validation success rates and unauthorized attempts

Learn More