Skip to main content

validate_property_delivery

AdCP 3.0 提案 - このタスクは AdCP 3.0 向けに開発中です。
配信記録をプロパティリストに照らして準拠性を検証します。次の 2 点を確認します:
  1. プロパティ準拠: インプレッションはリスト内プロパティに配信されたか?
  2. サプライパス認可: セールスエージェントにその在庫を売る権限があったか?

Use Cases

  • ポストキャンペーン検証: インプレッションが準拠プロパティに配信されたか確認
  • サプライパス検証: セールスエージェントがパブリッシャーに認可されていたか確認
  • リアルタイム監視: 実行中キャンペーンの準拠率を確認
  • 監査証跡: 規制・ブランドセーフティ審査向けレポート生成

Request

{
  "$schema": "/schemas/property/validate-property-delivery-request.json",
  "list_id": "pl_abc123",
  "records": [
    {
      "identifier": { "type": "domain", "value": "www.nytimes.com" },
      "impressions": 103
    },
    {
      "identifier": { "type": "domain", "value": "sketchy-site.example" },
      "impressions": 47
    },
    {
      "identifier": { "type": "android_package", "value": "com.unknown.app" },
      "impressions": 25
    }
  ],
  "include_compliant": false
}

Parameters

ParameterTypeRequiredDescription
list_idstringYes検証対象のプロパティリスト ID
recordsarrayYes検証する配信記録(1〜10,000 件)
records[].identifierobjectYesプロパティ識別子(typevalue
records[].impressionsintegerYes配信インプレッション数
records[].record_idstringNo相関用のクライアント ID
records[].sales_agent_urlstringNo認可検証に使うセールスエージェント URL(adagents.json と突き合わせ)
include_compliantbooleanNo準拠レコードを結果に含めるか(デフォルト false)

Response

{
  "$schema": "/schemas/property/validate-property-delivery-response.json",
  "list_id": "pl_abc123",
  "summary": {
    "total_records": 4,
    "total_impressions": 200,
    "compliant_records": 1,
    "compliant_impressions": 103,
    "non_compliant_records": 1,
    "non_compliant_impressions": 47,
    "not_covered_records": 1,
    "not_covered_impressions": 25,
    "unidentified_records": 1,
    "unidentified_impressions": 25
  },
  "aggregate": {
    "score": 68.7,
    "grade": "C+",
    "label": "68.7% compliant",
    "methodology_url": "https://governance.example.com/methodology/compliance-scoring"
  },
  "results": [
    {
      "identifier": { "type": "domain", "value": "sketchy-site.example" },
      "status": "non_compliant",
      "impressions": 47,
      "violations": [
        {
          "code": "not_in_list",
          "message": "Identifier not found in resolved property list"
        }
      ]
    },
    {
      "identifier": { "type": "domain", "value": "new-site.example" },
      "status": "not_covered",
      "impressions": 25
    },
    {
      "identifier": { "type": "android_package", "value": "com.unknown.app" },
      "status": "unidentified",
      "impressions": 25
    }
  ],
  "validated_at": "2026-01-04T19:00:00Z",
  "list_resolved_at": "2026-01-04T12:00:00Z"
}

レスポンスフィールド

FieldTypeDescription
list_idstring検証に用いたプロパティリスト ID
summaryobjectプロパティ準拠検証の生カウント
aggregateobject任意の算出指標(ガバナンスエージェント提供)
resultsarrayレコード単位の検証結果
validated_atdatetime検証日時
list_resolved_atdatetime使用したプロパティリストの解決タイムスタンプ

Summary フィールド

Summary は生カウントを提供し、率の算出はクライアント側で行います:
FieldDescription
total_recordsTotal records validated
total_impressionsTotal impressions across all records
compliant_records / compliant_impressionsRecords/impressions in the property list
non_compliant_records / non_compliant_impressionsRecords/impressions NOT in the property list
not_covered_records / not_covered_impressionsIdentifier recognized but no data available
unidentified_records / unidentified_impressionsIdentifier type not resolvable

検証ステータス

StatusMeaning
compliant解決済みリストに含まれる
non_compliant解決済みリストに含まれない
not_covered識別子は認識したがデータなし
unidentifiedこのエージェントでは解決できない識別子

not_covered と unidentified の違い

いずれも「未知」だが性質が異なります: not_covered - 識別子は認識した(例: 有効なドメイン)が、そのプロパティのデータがない場合。例:
  • プロパティが新しく DB に未登録
  • プロパティは存在するが未評価
  • エージェントのカバレッジ外カテゴリ
unidentified - 識別子を認識できない場合。例:
  • クライアント側でプロパティ検出に失敗
  • サポート外の識別子型(ドメインのみ対応だが App ID を受信など)
  • 値が不正
両者とも準拠率計算から除外します。検出やカバレッジの不足を罰するべきではありません。

Optional Aggregate Metrics

Governance agents can optionally return computed metrics in the aggregate field:
"aggregate": {
  "score": 68.7,
  "grade": "C+",
  "label": "68.7% compliant",
  "methodology_url": "https://governance.example.com/methodology"
}
FieldDescription
scoreNumeric score (scale is agent-defined, typically 0-100)
gradeLetter grade or category (e.g., “A+”, “B-”, “Gold”)
labelHuman-readable summary (e.g., “85% compliant”)
methodology_urlURL explaining how the aggregate was calculated
The aggregate field is optional and agent-specific. Consumers should not assume a particular format - always check methodology_url for interpretation.

Calculating Your Own Rates

The response always includes raw counts. Calculate rates as needed:
# Compliance rate (exclude unverifiable from denominator)
unverifiable = summary.not_covered_impressions + summary.unidentified_impressions
verifiable = summary.total_impressions - unverifiable
compliance_rate = summary.compliant_impressions / verifiable if verifiable > 0 else None
In the example above:
  • Compliant impressions: 103
  • Non-compliant impressions: 47
  • not_covered + unidentified impressions: 50 (excluded)
  • Compliance rate: 103 / (200 - 50) = 103 / 150 = 68.7%

Violation Codes

CodeDescription
not_in_listIdentifier not found in the resolved property list
excludedIdentifier explicitly excluded via exclude_identifiers filter
country_mismatchProperty lacks feature data for required countries
channel_mismatchProperty doesn’t support required channels
feature_failedProperty failed a feature_requirements filter

Feature Violation Details

When a property fails a feature requirement, the violation includes the feature details:
{
  "identifier": { "type": "domain", "value": "low-quality-site.example" },
  "status": "non_compliant",
  "impressions": 150,
  "violations": [
    {
      "code": "feature_failed",
      "message": "Property failed consent_quality requirement (min: 85)",
      "feature_id": "consent_quality",
      "requirement": {
        "min_value": 85
      }
    }
  ]
}
The feature_id and requirement fields are optional - they’re included when the violation is due to a feature requirement filter.

Supply Path Authorization

When sales_agent_url is provided in delivery records, the governance agent validates that the sales agent is authorized to sell the property by checking the publisher’s adagents.json.

Request with Authorization

{
  "list_id": "pl_abc123",
  "records": [
    {
      "identifier": { "type": "domain", "value": "www.nytimes.com" },
      "impressions": 103,
      "sales_agent_url": "https://legitimate-ssp.example.com"
    },
    {
      "identifier": { "type": "domain", "value": "www.nytimes.com" },
      "impressions": 50,
      "sales_agent_url": "https://unauthorized-reseller.example.com"
    }
  ]
}

Response with Authorization

When authorization is validated, each result includes an authorization field:
{
  "list_id": "pl_abc123",
  "summary": {
    "total_records": 2,
    "total_impressions": 153,
    "compliant_records": 2,
    "compliant_impressions": 153,
    "non_compliant_records": 0,
    "non_compliant_impressions": 0,
    "unknown_records": 0,
    "unknown_impressions": 0
  },
  "authorization_summary": {
    "records_checked": 2,
    "impressions_checked": 153,
    "authorized_records": 1,
    "authorized_impressions": 103,
    "unauthorized_records": 1,
    "unauthorized_impressions": 50,
    "unknown_records": 0,
    "unknown_impressions": 0
  },
  "results": [
    {
      "identifier": { "type": "domain", "value": "www.nytimes.com" },
      "status": "compliant",
      "impressions": 50,
      "authorization": {
        "status": "unauthorized",
        "publisher_domain": "nytimes.com",
        "sales_agent_url": "https://unauthorized-reseller.example.com",
        "violation": {
          "code": "agent_not_authorized",
          "message": "Sales agent not listed in nytimes.com/.well-known/adagents.json"
        }
      }
    }
  ],
  "validated_at": "2026-01-04T19:00:00Z"
}

Authorization Statuses

StatusMeaningIncluded in authorization_rate?
authorizedSales agent is listed in publisher’s adagents.jsonYes (numerator)
unauthorizedSales agent is NOT listed in publisher’s adagents.jsonYes (denominator only)
unknownCould not fetch or parse adagents.jsonNo (excluded)

Authorization Violation Codes

CodeDescription
agent_not_authorizedSales agent URL not found in publisher’s authorized_agents list
adagents_not_foundPublisher’s adagents.json could not be fetched (404, timeout, etc.)
adagents_invalidPublisher’s adagents.json exists but is malformed
property_not_declaredProperty identifier not declared in publisher’s adagents.json

Two Independent Checks

Property compliance and authorization are independent checks. A record can be:
Property StatusAuthorization StatusMeaning
compliantauthorizedFully valid - property in list, sold by authorized agent
compliantunauthorizedProperty is approved but sold by unauthorized reseller
non_compliantauthorizedAuthorized agent sold property outside your list
non_compliantunauthorizedNeither property nor agent validated
Both checks use the same “unknown excludes from rate” pattern - you cannot penalize for detection gaps.

Best Practices

Batch Validation

For large-scale validation, batch records up to the 10,000 limit:
def validate_delivery_batch(records, list_id, governance_agent):
    """Validate delivery records in batches."""
    batch_size = 10000
    all_results = []

    for i in range(0, len(records), batch_size):
        batch = records[i:i + batch_size]
        response = governance_agent.validate_property_delivery(
            list_id=list_id,
            records=batch
        )
        all_results.extend(response.results)

    return all_results

Sampling Strategy

For real-time monitoring during campaign execution, validate a statistical sample rather than all records:
import random

def sample_and_validate(records, sample_size=1000):
    """Validate a random sample for real-time monitoring."""
    sample = random.sample(records, min(sample_size, len(records)))
    return governance_agent.validate_property_delivery(
        list_id=list_id,
        records=sample
    )

Handling Unknown Records

Track unknown rates separately to identify detection gaps:
def analyze_validation(response):
    """Analyze validation results with unknown handling."""
    summary = response.summary

    # Core compliance metric
    compliance_rate = summary.compliance_rate

    # Detection quality metric
    unknown_rate = summary.unknown_impressions / summary.total_impressions

    if unknown_rate > 0.1:
        print(f"Warning: {unknown_rate:.1%} of impressions unresolvable")

    return {
        "compliance_rate": compliance_rate,
        "unknown_rate": unknown_rate,
        "non_compliant_impressions": summary.non_compliant_impressions
    }