Skip to main content
セラーアカウント上のファーストパーティ CRM オーディエンスを管理します。ハッシュ化された顧客リストをアップロードし、マッチングステータスを確認し、create_media_buy のターゲティングオーバーレイで結果のオーディエンスを参照して、明示的なリターゲティングやサプレッションに利用できます。 オーディエンスはシグナルとは異なります。シグナルはサードパーティデータプロダクトであり、ディスカバーして有効化するもの。オーディエンスは自社が所有してアップロードするデータです。audience_include を使うとアップロードしたリストのメンバーだけをターゲットにできます。audience_include はハード制約であり、リスト上のユーザーのみが対象となります。オーディエンスに類似した新規ユーザーを探す場合(類似オーディエンス拡張)は、キャンペーンブリーフにそのインテントを記述する — 拡張戦略はセラーが担当します。なお、ブリーフで表明された類似インテントはプロトコルを通じて検証できないため、セラー側のレポートで確認すること。 レスポンス時間: アップロードは約 1〜2 秒で受け付けられます。マッチングが完了するまでタスクはアクティブな状態が続く(セラーによって 1〜48 時間)。オーディエンスの準備ができたときに Webhook を受け取るには push_notification_config を設定すること。 リクエストスキーマ: /schemas/latest/media-buy/sync-audiences-request.json レスポンススキーマ: /schemas/latest/media-buy/sync-audiences-response.json

クイックスタート

顧客リストをアップロードしてステータスを確認します:
import { testAgent } from "@adcp/client/testing";
import { SyncAudiencesResponseSchema } from "@adcp/client";
import { createHash } from "crypto";

const hashEmail = (email) =>
  createHash("sha256").update(email.toLowerCase().trim()).digest("hex");

const hashPhone = (e164Phone) =>
  createHash("sha256").update(e164Phone).digest("hex");

const result = await testAgent.syncAudiences({
  account: { account_id: "acct_12345" },
  audiences: [
    {
      audience_id: "existing_customers",
      name: "Existing customers",
      add: [
        { external_id: "crm_1001", hashed_email: hashEmail("alice@example.com") },
        { external_id: "crm_1002", hashed_email: hashEmail("bob@example.com"), hashed_phone: hashPhone("+12065551234") },
      ],
    },
  ],
});

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

const validated = SyncAudiencesResponseSchema.parse(result.data);

if ("errors" in validated && validated.errors) {
  throw new Error(`Operation failed: ${JSON.stringify(validated.errors)}`);
}

if ("audiences" in validated) {
  for (const audience of validated.audiences) {
    console.log(`${audience.audience_id}: ${audience.action} (${audience.status ?? "n/a"})`);
    if (audience.status === "ready") {
      console.log(`  Matched ${audience.matched_count} of ${audience.uploaded_count} members (this sync)`);
    }
  }
}

リクエストパラメータ

パラメータ必須説明
accountaccount-refはいアカウント参照。{ "account_id": "..." } を渡すか、セラーが暗黙的な解決をサポートしている場合は { "brand": {...}, "operator": "..." } を渡します。
audiencesAudience[]いいえ同期するオーディエンス。省略した場合、呼び出しはディスカバリー専用となり、変更なしで既存のすべてのオーディエンスを返します。
delete_missingbooleanいいえtrue の場合、このリクエストに含まれていないアカウント上のバイヤー管理オーディエンスを削除する(デフォルト: false)。セラー管理のオーディエンスには影響しません。audiences 配列を省略した状態と組み合わせると、すべてのバイヤー管理オーディエンスが削除されるため注意すること。

Audience オブジェクト

フィールド必須説明
audience_idstringはいこのオーディエンスのバイヤー識別子。ターゲティングオーバーレイでオーディエンスを参照するために使用します。
namestringいいえ人間が読みやすい名前
deletebooleanいいえtrue の場合、このオーディエンスをアカウントから完全に削除します。その他のフィールドはすべて無視されます。
addAudienceMember[]いいえこのオーディエンスに追加するメンバー
removeAudienceMember[]いいえこのオーディエンスから削除するメンバー。同じ識別子が addremove の両方に現れた場合、remove が優先されます。
consent_basisstringいいえGDPR の適法根拠: consentlegitimate_interestcontract、または legal_obligation。規制対象市場の一部セラーで必須。

Audience メンバー

すべてのメンバーには external_id(バイヤーが割り当てた安定した識別子)と、少なくとも 1 つのマッチング可能な識別子が必要です。送信前にすべての値を SHA-256 でハッシュ化すること — メールアドレスは小文字化+トリム、電話番号は E.164 形式(例: +12065551234)に正規化します。
フィールド説明
external_idstring必須。 このメンバーのバイヤーが割り当てた安定した識別子(例: CRM レコード ID、ロイヤルティ ID)。重複排除、削除、バイヤーシステムとのクロスリファレンスに使用します。
hashed_emailstring小文字化・トリムされたメールアドレスの SHA-256 ハッシュ(64 文字の16進数)
hashed_phonestringE.164 形式の電話番号の SHA-256 ハッシュ(64 文字の16進数)
uidsUID[]ユニバーサル ID: type(rampid、uid2、maid など)+ value
同一人物に複数の識別子を提供するとマッチ率が向上します。複合識別子(例: ハッシュ化された姓名 + 郵便番号)はまだ標準化されていない — プラットフォーム固有の拡張には ext を使用すること。 識別子のサポートはセラーによって異なる: 送信前に get_adcp_capabilitiesmedia_buy.audience_targeting.supported_identifier_types および media_buy.audience_targeting.supported_uid_types を確認すること。MAID のサポートは全セラーに共通ではない(LinkedIn は MAID を受け付けない。iOS の IDFA には App Tracking Transparency の同意が必要)。ケイパビリティの media_buy.audience_targeting.matching_latency_hours の範囲と media_buy.audience_targeting.minimum_audience_size もセラー固有の値です。 サイズ制限: ペイロードはすべてのオーディエンスを合わせて 1 回の呼び出しにつき最大 100,000 メンバーに制限されます。より大きなリストの場合は、add のデルタを使って順次呼び出しに分割すること。 同時実行: sync_audience への呼び出しは互いに独立していることを確認すること。処理は順不同になる場合があります。順次実行が必要な場合は、設定した Webhook へのコールバックを受け取ってから次の呼び出しを行うこと。

レスポンス

成功レスポンス:
  • audiences — このリクエストに含まれていないオーディエンスも含む、アカウント上のすべてのオーディエンスの結果
エラーレスポンス:
  • errors — 操作レベルのエラーの配列(認証失敗、アカウントが見つからない場合など)
注意: レスポンスは識別共用体を使用している — 成功フィールドとエラーのどちらか一方のみが返され、両方が同時に返されることはない。 成功レスポンスの各オーディエンスに含まれるフィールド:
フィールド説明
audience_idリクエストから返されるバイヤーの識別子
seller_idセラーの広告プラットフォームで割り当てられた ID
actioncreatedupdatedunchangeddeleted、または failed
statusprocessingready、または too_small。action が createdupdated、または unchanged の場合に存在します。action が deleted または failed の場合は存在しません。
uploaded_countこの同期操作で送信されたメンバー数(差分、累積ではない)。ディスカバリー専用呼び出しでは 0。
total_uploaded_countすべての同期にわたってアップロードされたメンバーの累積数。matched_count と比較してマッチ率を計算します。
matched_countすべての同期にわたってプラットフォームユーザーにマッチしたメンバーの合計数(累積)。status: "ready" の時に設定されます。
effective_match_rateすべての識別子タイプにわたる重複排除済みのマッチ率(0〜1)。リーチ推定のための単一の数値。status: "ready" の時に設定されます。
match_breakdown識別子タイプ別のマッチ結果。どの ID タイプがどのマッチ率で解決されるかを示します。マッチ内訳を参照。
last_synced_at最新の同期の ISO 8601 タイムスタンプ。セラーがこれをトラッキングしていない場合は省略されます。
minimum_sizeこのプラットフォームでターゲティングするための最小マッチオーディエンスサイズ。status: "too_small" の時に設定されます。
errorsオーディエンスごとのエラー(action: "failed" の場合のみ)

マッチ内訳

セラーが識別子タイプ別のレポートをサポートしている場合、レスポンスには match_breakdown が含まれる — これはどの ID タイプが解決されているか、どのマッチ率かを示す配列です。バイヤーは将来のアップロードでどの識別子を優先すべきかを判断するために活用できます。
{
  "audience_id": "existing_customers",
  "action": "updated",
  "status": "ready",
  "uploaded_count": 5000,
  "total_uploaded_count": 25000,
  "matched_count": 18750,
  "effective_match_rate": 0.75,
  "match_breakdown": [
    { "id_type": "hashed_email", "submitted": 25000, "matched": 17500, "match_rate": 0.70 },
    { "id_type": "hashed_phone", "submitted": 15000, "matched": 12000, "match_rate": 0.80 },
    { "id_type": "rampid", "submitted": 8000, "matched": 7200, "match_rate": 0.90 }
  ]
}
主要なセマンティクス:
  • submittedmatched は累積値であり、すべての同期にわたる値で、total_uploaded_count のセマンティクス(uploaded_count ではない)に対応します。
  • effective_match_rate は重複排除済み — メールと電話の両方でマッチしたメンバーは 1 回としてカウントされます。タイプ別マッチ率の合計以下になります。
  • match_rate はサーバーが権威のある値 — コンシューマーは submitted/matched から自分で計算するよりもこの値を優先すべきです。
  • id_type の値は、ハッシュ化された PII タイプ(hashed_emailhashed_phone)とユニバーサル ID タイプ(rampiduid2id5euidpairidmaid)を組み合わせたものです。
集計マッチカウントのみをサポートするセラーは match_breakdown を完全に省略します。

よくあるシナリオ

ディスカバリー専用

変更なしで既存のすべてのオーディエンスのステータスを確認します。レスポンスにはアカウント上のすべてのオーディエンスが含まれる — audience_id でフィルタリングして目的のオーディエンスを見つけること:
import { testAgent } from "@adcp/client/testing";
import { SyncAudiencesResponseSchema } from "@adcp/client";

const result = await testAgent.syncAudiences({
  account: { account_id: "acct_12345" },
});

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

const validated = SyncAudiencesResponseSchema.parse(result.data);

if ("errors" in validated && validated.errors) {
  throw new Error(`Operation failed: ${JSON.stringify(validated.errors)}`);
}

if ("audiences" in validated) {
  for (const audience of validated.audiences) {
    console.log(`${audience.audience_id}: ${audience.status ?? "n/a"}`);
  }
}

サプレッションリスト

新規獲得キャンペーンから除外するために、既存顧客のリストをアップロードする:
import { testAgent } from "@adcp/client/testing";
import { SyncAudiencesResponseSchema } from "@adcp/client";
import { createHash } from "crypto";

const hashEmail = (email) =>
  createHash("sha256").update(email.toLowerCase().trim()).digest("hex");

// CRM エクスポートからのハッシュ化された顧客メールアドレス
const existingCustomers = [
  { hashed_email: hashEmail("customer1@example.com") },
  { hashed_email: hashEmail("customer2@example.com") },
];

const result = await testAgent.syncAudiences({
  account: { account_id: "acct_12345" },
  audiences: [
    {
      audience_id: "existing_customers",
      name: "Existing customers — suppression",
      add: existingCustomers,
    },
  ],
});

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

const validated = SyncAudiencesResponseSchema.parse(result.data);

if ("errors" in validated && validated.errors) {
  throw new Error(`Operation failed: ${JSON.stringify(validated.errors)}`);
}

if ("audiences" in validated) {
  const audience = validated.audiences[0];
  console.log(`Status: ${audience.status}`);
  // ready になったら、create_media_buy の targeting_overlay.audience_exclude で audience_id を参照する
}

メンバーの削除

オーディエンスを差分で更新する — 新しいメンバーを追加し、対象外になったメンバーを削除します:
import { testAgent } from "@adcp/client/testing";
import { SyncAudiencesResponseSchema } from "@adcp/client";
import { createHash } from "crypto";

const hashEmail = (email) =>
  createHash("sha256").update(email.toLowerCase().trim()).digest("hex");

const result = await testAgent.syncAudiences({
  account: { account_id: "acct_12345" },
  audiences: [
    {
      audience_id: "lapsed_subscribers",
      name: "Lapsed subscribers",
      add: [{ hashed_email: hashEmail("newlapse@example.com") }],
      remove: [{ hashed_email: hashEmail("reactivated@example.com") }],
    },
  ],
});

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

const validated = SyncAudiencesResponseSchema.parse(result.data);

if ("errors" in validated && validated.errors) {
  throw new Error(`Operation failed: ${JSON.stringify(validated.errors)}`);
}

if ("audiences" in validated) {
  for (const audience of validated.audiences) {
    console.log(`${audience.audience_id}: ${audience.action}`);
  }
}

オーディエンスの削除

他のオーディエンスに影響を与えずに特定のオーディエンスをアカウントから削除します。オーディエンスオブジェクトに delete: true を設定します:
import { testAgent } from "@adcp/client/testing";
import { SyncAudiencesResponseSchema } from "@adcp/client";

const result = await testAgent.syncAudiences({
  account: { account_id: "acct_12345" },
  audiences: [
    { audience_id: "old_campaign_list", delete: true },
  ],
});

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

const validated = SyncAudiencesResponseSchema.parse(result.data);

if ("audiences" in validated) {
  const audience = validated.audiences.find(a => a.audience_id === "old_campaign_list");
  console.log(`${audience.audience_id}: ${audience.action}`); // "deleted"
}
1 回の呼び出しで複数のオーディエンスを削除するには、それぞれに delete: true を指定します。すべてのバイヤー管理オーディエンスを一度に削除するには、空の audiences 配列と delete_missing: true を使用する — ただし、すべてが削除されるため注意すること。

メディアバイでのオーディエンスの使用

オーディエンスが ready になったら、create_media_buy のターゲティングオーバーレイで audience_id を参照します。オーディエンス ID はセラーアカウントにスコープされるため、セラーをまたいで使用することはできません。
test=false
{
  "brand": { "house_domain": "acme.com", "brand_id": "main" },
  "start_time": "asap",
  "end_time": "2026-03-31T23:59:59Z",
  "packages": [
    {
      "product_id": "prod_sponsored_content",
      "pricing_option_id": "cpm_standard",
      "budget": 10000,
      "targeting_overlay": {
        "audience_include": ["high_value_prospects"],
        "audience_exclude": ["existing_customers"]
      }
    }
  ]
}

オーディエンスステータス

プラットフォームのマッチングは非同期です。status フィールドは現在の状態を反映する:
ステータス意味
processingプラットフォームがアップロードされたメンバーをユーザーベースと照合中。後でもう一度確認すること — まだキャンペーンを作成してはいけない。
readyオーディエンスはターゲティングに使用可能。matched_count が設定されています。
too_smallマッチしたオーディエンスがプラットフォームの最小サイズを下回っています。レスポンスの minimum_size でしきい値を確認できます。メンバーを追加して再同期すること。
statusactioncreatedupdated、または unchanged の場合に存在します。actiondeleted または failed の場合は存在しません。 Webhook(推奨): アップロード前にプロトコルレベルで push_notification_config を設定すること。タスクはセラーのプラットフォームがメンバーをマッチングしている間アクティブな状態が続く。マッチングが完了すると、タスクが完了し、最終結果(status: "ready" または status: "too_small")とともに Webhook が発火します。現実的な期待値を設定するには get_adcp_capabilitiesaudience_targeting.matching_latency_hours を確認すること(通常 1〜48 時間)。 ポーリングフォールバック: Webhook を使用しない場合は、audiences を省略したディスカバリー専用呼び出しで 15 分以上の間隔でポーリングすること。タスクのステータスを確認するには tasks/gettask_id を使用する — マッチング処理中はタスクが submitted 状態になり、オーディエンスの準備が完了するか小さすぎる場合に completed になります。 エージェントワークフロー: push_notification_config を設定してアップロードします。セッション終了前に audience_idaccount_id を外部化します。status: "ready" の Webhook が発火したら再開して create_media_buy に進む。

ハッシュ化の要件

送信前にすべての識別子を SHA-256 でハッシュ化すること。まず正規化を行う:
識別子正規化
メールアドレス小文字化、前後の空白を除去alice@example.com → ハッシュ
電話番号E.164 形式+12065551234 → ハッシュ
MAID正規化不要そのまま使用
test=false
import { createHash } from "crypto";

const hashEmail = (email) =>
  createHash("sha256").update(email.toLowerCase().trim()).digest("hex");

const hashPhone = (e164Phone) =>
  createHash("sha256").update(e164Phone).digest("hex");

プライバシーに関する考慮事項

すべての PII はバイヤーが送信前にハッシュ化する — プロトコルは平文の個人データを一切扱わない。SHA-256 ハッシュは一方向であり、元のメールアドレスや電話番号に逆変換することはできません。セラーは同じアルゴリズムで自社のユーザーデータを独立してハッシュ化することでマッチングを行います。 バイヤーの義務: バイヤーは管轄区域に関わらず、オーディエンスデータを処理・共有するための適法根拠を持つ責任があります。規制対象市場で活動するセラーに GDPR の適法根拠を伝えるために、各オーディエンスに consent_basis を含めること — 一部のセラーは EU オーディエンスに対してこのフィールドを必須としています。 データ取り扱い: アップロード後のデータ処理と保持は、セラーとの契約に基づいて管理されます。オーディエンスデータをアップロードする前に、セラーのデータ処理条件を確認すること。

エラー処理

エラーコード説明対処方法
ACCOUNT_NOT_FOUNDアカウントが存在しないaccount_id を確認する
AUDIENCE_NOT_FOUND削除対象のオーディエンスが存在しないaudience_id を確認するか remove を省略する
INVALID_HASH_FORMAT識別子が期待されるハッシュ形式と一致しないSHA-256 の16進数エンコードを確認する(64 文字、小文字)
RATE_LIMITED同期リクエストが多すぎる指数バックオフで再試行します。ポーリングは 15 分以上の間隔で行うこと
CALL_TOO_LARGEペイロードのメンバー数が多すぎるペイロードはすべてのオーディエンスを合わせて最大 100,000 メンバーに制限される

次のステップ