Skip to main content
1つ以上のブランド/オペレーターのペアに対してセラーと広告主アカウントを同期します。セラーはアカウントをプロビジョニングまたはリンクし、アカウントごとのステータスとセットアップ手順を返します。ブランドは domain + オプションの brand_id を含む brand オブジェクトで識別され、/.well-known/brand.json 経由で解決されます。 sync_accounts はすべてのセラープロトコルで使用されます: メディアバイエージェント、シグナルエージェント、ガバナンスエージェント、クリエイティブエージェント。バイヤーの意図を宣言し、セラーが内部でアカウントをプロビジョニングまたはリンクします。暗黙的アカウント(require_operator_auth: false)の場合、後続のリクエストには自然キー(brand + operator)を使用します。明示的アカウント(require_operator_auth: true)の場合、セラーが割り当てたアカウント ID を list_accounts で探索します。暗黙的アカウントのサンドボックスには、アカウントエントリに sandbox: true を含める — セラーは実際の支出なしでテストアカウントをプロビジョニングします。明示的アカウントの場合、サンドボックスアカウントは list_accounts で探索する既存のテストアカウントです。 応答時間: 約1秒。アカウントプロビジョニングは同期的; 与信審査や法的レビューには人間の対応が必要な場合がある(setup.url 付きの status: "pending_approval" で示されます)。 リクエストスキーマ: /schemas/v3/account/sync-accounts-request.json レスポンススキーマ: /schemas/v3/account/sync-accounts-response.json

クイックスタート

単一の広告主アカウントを同期して結果のステータスを確認します。
import { testAgent } from "@adcp/client/testing";
import { SyncAccountsResponseSchema } from "@adcp/client";

const result = await testAgent.syncAccounts({
  accounts: [
    {
      brand: { domain: "acme-corp.com" },
      operator: "acme-corp.com",
      billing: "operator",
    },
  ],
});

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

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

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

for (const account of validated.accounts) {
  console.log(`${account.brand.domain}: ${account.status}`);
  if (account.status === "pending_approval" && account.setup?.url) {
    console.log(`  Complete setup at: ${account.setup.url}`);
  }
}

リクエストパラメーター

パラメーター必須説明
accountsarrayYes同期するアカウントエントリの配列(下記参照)。
delete_missingbooleanNotrue の場合、このエージェントが以前に同期したがこのリクエストに含まれないアカウントを非アクティブ化します。認証済みエージェントにスコープされます。デフォルト: false
dry_runbooleanNotrue の場合、変更を適用せずにプレビューします。デフォルト: false
push_notification_configobjectNoアカウントステータス変更時の非同期通知用 Webhook(例: pending_approval から active への遷移)。
アカウントエントリのフィールド:
フィールド必須説明
brandobjectYes広告主を識別するブランド参照。domain(brand.json がホストされているハウスドメイン)とオプションの brand_id(マルチブランドハウス用)を含みます。brand-ref を参照。
operatorstringYesブランドの代理で活動するエンティティのドメイン(例: pinnacle-media.com)。ブランドが直接運営する場合はブランドのドメインに設定。brand.json の authorized_operators に対して検証されます。
billingstringYes請求先: operator または agent。セラーが受け入れる内容を確認するには get_adcp_capabilitiessupported_billing を確認します。セラーはこの請求モデルを受け入れるかリクエストを拒否しなければなりません。
payment_termsstringNoこのアカウントの支払い条件: net_15net_30net_45net_60net_90prepay。セラーはこれらの条件を受け入れるかアカウントを拒否しなければなりません — 条件は暗黙的に変更されない。省略時、セラーはデフォルト条件を適用します。
sandboxbooleanNotrue の場合、実際のプラットフォーム呼び出しや請求なしでサンドボックスアカウントを設定します。暗黙的アカウント(require_operator_auth: false)にのみ適用。明示的アカウントの場合、サンドボックスアカウントは list_accounts で探索する既存のテストアカウント。
governance_agentsarrayNoこのアカウントのガバナンスエージェントエンドポイント。存在する場合、セラーはメディアバイリクエストを確認する前にこれらのエージェントをガバナンス承認のために呼び出さなければなりません。各エントリには urlauthentication、エージェントが処理する検証カテゴリをスコープするオプションの categories を含みます。資格情報のローテーションには、更新された authentication で sync_accounts を再呼び出しします。
自然キー: タプル (brand, operator, sandbox) がアカウント関係を一意に識別します。{brand: {domain: "acme-corp.com"}, operator: "acme-corp.com"}(直接)は {brand: {domain: "acme-corp.com"}, operator: "pinnacle-media.com"}(代理店経由)とは異なるアカウント。sandbox: true を追加すると、同じブランド/オペレーターのペアに対してサンドボックスアカウントがプロビジョニングされる — 実際のプラットフォーム呼び出しや請求なし。

レスポンス

成功レスポンス: アカウントごとの結果を含む accounts 配列を返します。操作が成功しても、個々のアカウントが保留中、拒否、または失敗することがあります。 エラーレスポンス:
  • errors — 操作レベルのエラーの配列(認証失敗、サービス利用不可)。accounts 配列は含まれない。
注: レスポンスは判別共用体を使用 — accounts または errors のいずれか一方のみ、両方は含まれない。 アカウントごとのフィールド:
フィールド説明
brandリクエストからエコーされます。domain とオプションの brand_id を含むオブジェクト。
operatorリクエストからエコーされます。
nameアカウントのセラー表示名。
action実行された内容: createdupdatedunchangedfailed
statusアカウントの現在の状態(アカウントステータス を参照)。
billing適用された請求モデル。リクエストの値と一致します。
account_scopeセラーがアカウントをスコープした方法: operator(このオペレーターのブランド間で共有)、brand(このブランドのオペレーター間で共有)、operator_brand(このオペレーター+ブランドのペア専用)、agent(エージェントのデフォルトアカウント)。アカウントスコープ を参照。
setupstatus: "pending_approval" の場合に存在。与信または法的セットアップ完了の url、必要な内容を説明する message、オプションの expires_at を含みます。
rate_cardセラーが割り当てたレートカード識別子(該当する場合)。
payment_termsこのアカウントで合意した支払い条件: net_15net_30net_45net_60net_90prepay。アカウントがアクティブな場合、すべての請求書の拘束力を持つ条件。
credit_limit最大未払い残高({amount, currency})。
errorsアカウントごとのエラー(action: "failed" の場合のみ存在)。
warnings非致命的な通知。
governance_agentsリクエストで提供された場合にエコーされるガバナンスエージェントエンドポイント。
sandboxこれがサンドボックスアカウントかどうか、リクエストからエコーされます。暗黙的アカウントにのみ存在。

アカウントステータス

ステータス意味次のステップ
active使用準備完了プロトコル操作で アカウント参照 を使用
pending_approvalセラーがレビュー中与信または法的プロセスを完了するために人間が setup.url にアクセスする必要がある場合があります。更新確認のため list_accounts をポーリング。
rejectedセラーがリクエストを拒否warnings の拒否理由を確認し、調整して再試行するかセラーに連絡
payment_required与信限度額超過または残高不足資金追加または与信限度額引き上げ。他のアカウントに支出を振り分ける。
suspendedアクティブだったが現在停止中セラーに連絡して解決
closedアクティブだったが現在終了

非同期通知

push_notification_config が提供され、セラーが pending_approval を返した場合、アカウントステータスが変更されると(例: 承認 → active、拒否 → rejected)、セラーはWebhook通知を送信します。 通知ペイロードには (brand, operator) の自然キーが含まれるため、バイヤーは元の同期リクエストと関連付けられます。明示的アカウント(require_operator_auth: true)の場合、プロビジョニング後にセラーが割り当てた account_id も通知に含まれます。
{
  "brand": { "domain": "nova-brands.com", "brand_id": "glow" },
  "operator": "pinnacle-media.com",
  "status": "active",
  "account_id": "acc_glow_001"
}
バイヤーが push_notification_config を提供しなかった場合、ステータス変更を確認するために list_accounts をポーリングします。

一般的なシナリオ

複数のブランドを同期する代理店

import { testAgent } from "@adcp/client/testing";
import { SyncAccountsResponseSchema } from "@adcp/client";

const result = await testAgent.syncAccounts({
  accounts: [
    {
      brand: { domain: "nova-brands.com", brand_id: "spark" },
      operator: "pinnacle-media.com",
      billing: "operator",
    },
    {
      brand: { domain: "nova-brands.com", brand_id: "glow" },
      operator: "pinnacle-media.com",
      billing: "operator",
    },
  ],
});

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

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

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

for (const account of validated.accounts) {
  if (account.status === "active") {
    console.log(`Ready: ${account.brand.domain}/${account.brand.brand_id}${account.status}`);
  } else if (account.status === "pending_approval") {
    console.log(`Setup required for ${account.brand.brand_id}: ${account.setup?.url}`);
    // アクティブになるまで list_accounts をポーリング
  }
}

ブランドによる直接購入

import { testAgent } from "@adcp/client/testing";
import { SyncAccountsResponseSchema } from "@adcp/client";

const result = await testAgent.syncAccounts({
  accounts: [
    {
      brand: { domain: "acme-corp.com" },
      operator: "acme-corp.com",
      billing: "operator",
    },
  ],
});

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

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

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

const account = validated.accounts[0];
if (account.status === "active") {
  console.log(`Ready: ${account.brand.domain}${account.status}`);
} else if (account.status === "pending_approval") {
  console.log(`Setup required: ${account.setup?.url}`);
  // アクティブになるまで list_accounts をポーリング
}

拒否の処理

セラーがリクエストを拒否した場合、アカウントエントリは status: "rejected" を持ちます。
import { testAgent } from "@adcp/client/testing";
import { SyncAccountsResponseSchema } from "@adcp/client";

const result = await testAgent.syncAccounts({
  accounts: [
    {
      brand: { domain: "acme-corp.com", brand_id: "clearance" },
      operator: "acme-corp.com",
    },
  ],
});

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

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

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

for (const account of validated.accounts) {
  if (account.status === "rejected") {
    console.log("Account request was rejected");
    if (account.warnings?.length) {
      console.log(`Reason: ${account.warnings.join(", ")}`);
    }
  }
}

エラーハンドリング

エラーコード説明解決策
ACCOUNT_NOT_FOUND参照されたアカウントが存在しないか、アクセスできないaccount_id を確認するか、再同期する
BILLING_NOT_SUPPORTEDセラーがリクエストされた請求モデルをサポートしていないsupported_billingget_adcp_capabilities を確認し、調整または billing を省略
PAYMENT_TERMS_NOT_SUPPORTEDセラーがリクエストされた支払い条件を受け入れないセラーのデフォルトを受け入れるため payment_terms を省略するか、オフラインで交渉
PAYMENT_REQUIREDアカウントが与信限度額に達した資金を追加するか、別のアカウントに振り分ける
ACCOUNT_SUSPENDEDアカウントが停止されているセラーに連絡して解決
BRAND_REQUIREDブランド参照なしで請求可能な操作が試みられたリクエストに brand を含める

次のステップ