Skip to main content
The v2 API is in active development. The onboarding flow described here may evolve before general availability.

Overview

A Storefront is your buyer-facing home on Interchange: the business presence, name, description, and discovery surface buyers use to understand who they are buying from. Your Merchandising Agent runs that Storefront, implements the AdCP media-buy workflow, and draws from the inventory sources you connect. The seller journey has four user-visible steps, mirroring the in-app onboarding UI:
  1. Verify your company — resolve your brand from the AAO registry, set your operator domain, and auto-verify (or fall back to manual KYC).
  2. Connect inventory sources — register one or more inventory sources: an external sales agent, your own ad server with Interchange-managed sales-agent plumbing, or another Storefront.
  3. Set up billing (optional by default) — connect Stripe to let Scope3 clear payments. Becomes required once a connected source advertises agent billing (accounts.supported_billing contains "agent") — buyers can ask Scope3 to clear in that case, so Stripe Connect is needed. If you skip this step on an optional Storefront, it operates on external agreements with buyers only — Scope3 will not clear payments and you must bill the buyer directly.
  4. Go live — confirm readiness and flip the storefront to ACTIVE. This opens the Storefront for transactions, then Scope3 reviews it before listing it in public buyer discovery.
A few helper endpoints support these steps but are not standalone “steps”:
  • POST /resolve-brand — looks up your brand in the AAO registry. Used inside Step 1 to pre-fill the form.
  • GET /discover-agents — surfaces agents AAO knows about for your domain. Used inside Step 2.
  • GET /readiness — a status query you can call any time to see what gates remain. Surfaced in Step 4 (and re-run server-side at activation).
Each customer has one storefront, and each storefront can connect one or more inventory sources. There is no customerId path parameter — the storefront is resolved from your API key’s customer context.

Who this is for

  • Publishers and sales houses connecting their inventory to agentic buyers
  • Retail media networks exposing on-site or off-site inventory through AdCP-compatible agents
  • Any seller who wants buyer agents (e.g. Scope3, Claude, custom buyers) to be able to discover and transact against their inventory

Prerequisites

1

Scope3 API key

Generate a key at interchange.io/user-api-keys. Keys start with scope3_ and authorize all storefront endpoints.
2

A registered brand on AAO

Your brand should have a brand.json published and resolvable through the AAO registry at agenticadvertising.org. If you don’t have one yet, the resolve-brand call returns a builderUrl that points you to the registry’s brand builder.
3

At least one inventory source

An external AdCP-compatible sales agent, an operator-owned ad server, or another Storefront. For external agents, you’ll need the endpoint URL, protocol, and (for non-OAuth agents) auth credentials.
4

Optional: Stripe account

Required only if you want Scope3 to settle payments through your storefront. Stripe Connect provisioning is gated to non-child customer accounts. When you connect, you pick the country your business is based in — it is permanent and sets your payout currency, so choose a Stripe-supported country that matches your storefront’s settlement currency.

Onboarding flow

1

Verify your company

The first thing a seller does is identify their company so Scope3 can pull their brand profile from AAO and validate the operator domain. This step combines a brand lookup, a storefront update, and an automatic operator-domain verification check.

1. Resolve your brand (helper)

Look up your brand in the AAO registry to grab the canonical brand name and logo URL. This call has no side effects — it’s only used to populate the storefront update payload.
curl -X POST https://api.interchange.io/api/v2/storefront/resolve-brand \
  -H "Authorization: Bearer scope3_..." \
  -H "Content-Type: application/json" \
  -d '{ "domain": "acme.com" }'
Response (resolved)
{
  "resolved": true,
  "domain": "acme.com",
  "brandName": "Acme",
  "logoUrl": "https://cdn.example.com/acme-logo.svg",
  "manifestUrl": "https://acme.com/.well-known/brand.json",
  "manifest": { "...": "full brand.json" },
  "registryEntry": { "...": "AAO registry entry" },
  "authorizedOperators": [
    { "domain": "acme-media.com", "scope": "primary" }
  ],
  "houseBrand": false
}
If no manifest is found, the call returns 200 with { "resolved": false, "builderUrl": "https://agenticadvertising.org/brand" } — point the operator at the builder URL to publish a brand.json.
The domain field is validated against a strict FQDN regex. IP addresses and internal hostnames are rejected to prevent SSRF.

2. Write the brand fields onto your storefront

If your customer doesn’t yet have a storefront record, create one first:
curl -X POST https://api.interchange.io/api/v2/storefront \
  -H "Authorization: Bearer scope3_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Media",
    "publisherDomain": "acme.com",
    "plan": "basic"
  }'
POST /storefront is idempotent — if a storefront already exists for your customer, the existing record is returned instead of creating a duplicate.Then update it with the brand fields from resolve-brand plus your operator domain:
curl -X PUT https://api.interchange.io/api/v2/storefront \
  -H "Authorization: Bearer scope3_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operatorDomain": "scope3.com",
    "brandName": "Acme",
    "logoUrl": "https://cdn.example.com/acme-logo.svg"
  }'
Response
{
  "platformId": "acme-media",
  "name": "Acme Media",
  "publisherDomain": "acme.com",
  "operatorDomain": "scope3.com",
  "brandName": "Acme",
  "logoUrl": "https://cdn.example.com/acme-logo.svg",
  "operatorDomainVerified": true,
  "plan": "basic",
  "status": "PENDING",
  "createdAt": "2026-04-25T12:00:00.000Z",
  "updatedAt": "2026-04-25T12:00:00.000Z"
}
When you set operatorDomain, the API automatically compares it against your customer’s registered customerDomain (and your parent customer’s, if applicable). If they match, operatorDomainVerified flips to true immediately. Otherwise a verification request is sent to Scope3 staff and you’ll need a manual KYC review.The flag is recomputed only when the operator domain actually changes — manual superadmin verifications are preserved across unrelated edits.
Updatable fields on PUT /storefront: name, publisherDomain, plan, status, operatorDomain, brandName, logoUrl. At least one field must be provided.
2

Connect inventory sources

An inventory source binds a named slot inside your Storefront to something your Merchandising Agent can draw from: an external ADCP-compatible sales agent, an operator-owned ad server with Interchange-managed sales-agent plumbing behind it, or another Storefront. Buyer-side discovery surfaces your Merchandising Agent as the ADCP actor for the Storefront, and discovery or media-buy calls route through the active source behind it.

1. Discover agents (helper)

Optional but recommended: see what AAO already knows about your domain. This proxies AAO’s operator and publisher endpoints plus your .well-known/adagents.json.
curl "https://api.interchange.io/api/v2/storefront/discover-agents?domain=acme.com" \
  -H "Authorization: Bearer scope3_..." \
  -H "x-aao-api-key: aao_..."
The x-aao-api-key header is optional. Without it you only get the public registry view. Pass it to also surface storyboard compliance status for agents you operate.
Response
{
  "domain": "acme.com",
  "operator": {
    "domain": "acme.com",
    "member": { "slug": "acme-media", "display_name": "Acme Media" },
    "agents": [
      {
        "url": "https://agent.acme-media.com/mcp",
        "name": "Acme Media Sales",
        "type": "SALES",
        "compliance": {
          "status": "passing",
          "storyboards_passing": 12,
          "storyboards_total": 12,
          "headline": "All scenarios pass"
        }
      }
    ]
  },
  "publisher": {
    "domain": "acme.com",
    "adagents_valid": true,
    "properties": [ { "id": "acme-app", "type": "mobile_app", "name": "Acme App" } ],
    "authorized_agents": [
      { "url": "https://agent.acme-media.com/mcp", "authorized_for": ["display"] }
    ]
  }
}
Responses are cached server-side for 2 minutes per (domain, key fingerprint). Pass &refresh=true to force a re-fetch.

2. Register an inventory source

curl -X POST https://api.interchange.io/api/v2/storefront/inventory-sources \
  -H "Authorization: Bearer scope3_..." \
  -H "Content-Type: application/json" \
  -d '{
    "sourceId": "acme-sales",
    "name": "Acme Media Sales",
    "executionType": "AGENT",
    "type": "SALES",
    "endpointUrl": "https://agent.acme-media.com/mcp",
    "protocol": "MCP",
    "authenticationType": "API_KEY",
    "auth": { "type": "bearer", "token": "agent_abc123..." },
    "description": "Primary external sales agent for Acme on-site display + CTV"
  }'
Required when executionType: "agent": type, endpointUrl, protocol, authenticationType. auth is required for API_KEY, JWT, and BASIC_AUTH agents and must be omitted for OAUTH and NO_AUTH.
Inventory-source credentials (API keys, Basic usernames/passwords, and JWT private keys) are encrypted at rest and only referenced by an opaque auth_secret_ref in the database. They are never echoed back in API responses (the response surfaces authConfigured: true instead). Never log, screenshot, or commit raw credentials to source control. Rotate immediately if a credential is exposed.
{
  "authenticationType": "API_KEY",
  "auth": { "type": "bearer", "token": "agent_abc123..." }
}
Token formats bearer, apikey, and api_key are all accepted. The token is encrypted at rest and never echoed back. The source goes to pending and auto-activates once the agent is reachable with the credential.
Response
{
  "sourceId": "acme-sales",
  "name": "Acme Media Sales",
  "executionType": "AGENT",
  "status": "PENDING",
  "agentId": "agent_01HX...",
  "type": "SALES",
  "endpointUrl": "https://agent.acme-media.com/mcp",
  "protocol": "MCP",
  "authenticationType": "API_KEY",
  "authConfigured": true,
  "createdAt": "2026-04-25T12:05:00.000Z",
  "updatedAt": "2026-04-25T12:05:00.000Z"
}
Compliance is checked at connect time and again at activation. Connect-time only requires that the agent is registered with AAO; failing or pending agents can still be connected.
AAO statusConnect a sourceSet storefront ACTIVE
passingOKOK
pendingOK (logged)Blocked until it flips to passing
not-passingOK (logged)Blocked until the agent passes
not-registeredRejected with VALIDATION_ERRORn/a
AAO unreachableRejected with SERVICE_UNAVAILABLE — retry once it recoversn/a
The activation gate is enforced by the agent_status / agent_connectivity readiness checks (see Step 4) — non-passing agents leave the storefront in a blocked state until compliance flips. The connect-time AAO registry gate runs uniformly for every caller — there is no SuperAdmin bypass.
Storefronts can connect as many external AGENT inventory sources as needed — no per-plan cap is enforced today. Ad-server-backed inventory sources (MANAGED_SALES_AGENT) are slot-exempt regardless of plan.Updates are partial — PUT /api/v2/storefront/inventory-sources/:sourceId accepts any subset of name, description, endpointUrl, protocol, authenticationType, auth, status. Updating auth rotates the stored credential; omitting it preserves the existing one.

3. How buyers discover this storefront

Once a Storefront is transacting, buyer discovery can surface its Merchandising Agent as a first-class ADCP sales agent with ID storefront-{platform_id}, where platform_id is the Storefront’s public platformId slug. Buyers call the Storefront surface; they do not target inventory source IDs directly in buyer discovery.get_products behavior depends on the storefront mode:
  • Composition — the Merchandising Agent composes buyer-facing products from active ingredient sources plus the active operating instructions.
  • Passthrough — the Merchandising Agent proxies get_products to an active source and returns the upstream products with Storefront identity overlaid.
Matching buyer instructions are resolved at get_products time using operator domain, brand domain, and optional country. Composition storefronts apply them during composition; passthrough storefronts apply them as response overlays, including discounts and notes. Without at least one active source, buyer get_products has nothing to compose from or proxy to.
Execution-specific configuration (per integration knobs — e.g. ad-server adapter settings for Interchange-managed ad-server sources) lives in typed fields per integration type, not in a generic config bag. New integration types add their own typed fields rather than overloading a polymorphic blob.
Ad-server-backed inventory sources (executionType: "MANAGED_SALES_AGENT") wire your Storefront to one of three operator-owned ad-server adapters. Interchange manages the AdCP plumbing behind your ad server. Pick one when creating the connection via POST /api/v2/storefront/esa:
AdapterCredentials you supplyHow Scope3 handles them
Google Ad Manager (google_ad_manager)Numeric network code.Scope3 provisions a per-customer service account; you grant it access in your GAM admin console.
SpringServe (springserve)Login email + password, or a pre-minted API token.Forwarded to the managed ad-server source at provision time and never persisted by Scope3. The source mints a fresh 2-hour token from email/password and auto-refreshes.
FreeWheel (freewheel)Publisher API username + password, or a 7-day temporary access key (advanced / testing only).Forwarded to the managed ad-server source at provision time and never persisted by Scope3. Username/password authenticates via the OAuth2 password grant and auto-refreshes.
Only non-secret display fields (login, environment, default advertiser/demand-partner id) are stored on the connection row so the UI can render “connected as …”. Rotating credentials on a live ad-server source preserves products, principals, and sync history via PUT /api/v2/storefront/inventory-sources/{sourceId}/adapter-config.
Some storefronts route directly to a wired provider adapter rather than an inventory-source sales agent. Supported adapter provider values are amazon, audiostack, google, meta, pinterest, reddit, snap, spotify, and tiktok.Delegated OAuth for these adapter storefronts uses the shared adapter callback path:
https://api.interchange.io/oauth/adapters/{provider}/callback
Register the same path on staging when testing, for example https://api.staging.interchange.io/oauth/adapters/snap/callback.
For FreeWheel and SpringServe, prefer the storefront credential screen for passwords and tokens rather than pasting secrets into chat. Murph can send the operator directly to the secure form with /{customerId}/storefront?tab=sources&connectAdServer=freewheel or /{customerId}/storefront?tab=sources&connectAdServer=springserve. That link opens Inventory sources, launches Connect ad server, and preselects the right adapter. Murph can then wait for submission, list the ad-server sources to find the new or updated connection, and run POST /api/v2/storefront/esa/{esaId}/test-connection to verify that the upstream source can authenticate.For testing, use a temporary API token when the ad server supports one. For production, username/password is usually better because the upstream source can mint and refresh short-lived tokens automatically. In either case, Scope3 stores only non-secret display fields; the upstream source holds the encrypted secret.

Uploading setup documents to Murph

Murph can use uploaded PDFs, decks, spreadsheets, images, and text documents during storefront setup. Use this for brand books, media kits, operating instructions, rate cards, do-not-air lists, and other materials that would otherwise need to be pasted into chat.Uploaded documents are summarized instead of copied back verbatim. The document-processing status includes:
FieldTypeDescription
extractedFactsarrayStructured facts extracted from the uploaded files. Each fact includes type, content, confidence, entities, and tags so Murph can reference the source material in later turns without re-reading the full file.
brandManifestCandidateobject | nullPresent when a brand book or visual identity document includes fields that may map into AAO brand.json. Includes status, confidence, rationale, mappedFields, missingInputs, and recommendedActions.
For brand books, Murph can identify brand.json candidates such as name, website URL, colors, fonts, tone, tagline, contact details, and disclaimers. Logo images can be uploaded to AAO for review; pending uploads are not public and are not written into brand.json until AAO approves and lists the /assets/brands/... URL. Other assets still need public hosted URLs before they can be used in brand.json.
Murph can draft and preview brand.json fields from an uploaded brand book, then compare those fields against the current AAO brand.json state and publish the confirmed manifest to AAO for your verified storefront operator domain. Uploaded logo images can be sent to AAO review from Murph; only approved AAO asset URLs or other public HTTPS URLs are written as logo or asset entries.
Google Ad Manager does not require the publisher to paste a password or API token into Scope3. Scope3 creates a per-customer service account and returns its email address from POST /api/v2/storefront/esa/service-account. The publisher grants that service-account email access inside their GAM network, then Scope3 provisions the ad-server-backed source with the publisher’s numeric network code.The operator-owned part of the flow is:
  1. Call POST /api/v2/storefront/esa/service-account and copy the returned serviceAccountEmail.
  2. In Google Ad Manager, go to Admin → Global settings → Network settings → Add a service account user.
  3. Enter the service-account email returned by Scope3.
  4. Grant a role that can read inventory and traffic campaigns, such as Trafficker or a least-privilege custom role with equivalent API permissions.
  5. Wait a few minutes for the grant to propagate.
  6. Create the ad-server source with POST /api/v2/storefront/esa and body { "type": "google_ad_manager", "networkCode": "12345678" }.
If the probe returns ADAPTER_PERMISSION_DENIED, verify that the exact service-account email was added and wait a minute or two before retrying. If it returns ADAPTER_NETWORK_NOT_FOUND, the network code is likely wrong.

GAM buyer-routing default advertiser

For Google Ad Manager managed-sales-agent sources, Storefront can clear the Default GAM advertiser setup blocker through the API. List cached advertiser records with GET /api/v2/storefront/esa/{esaId}/gam/advertisers, or create or find the intended catch-all advertiser with POST /api/v2/storefront/esa/{esaId}/gam/advertisers/ensure. Then set the tenant default with PUT /api/v2/storefront/esa/{esaId}/gam/default-advertiser using the returned advertiser.id.This flow configures the upstream sales-agent tenant directly. Operators do not need to open the embedded sales-agent UI to set the default GAM advertiser.Keep detailed GAM UI wording anchored to Google’s own support documentation; Scope3 docs should describe the contract we own, the service-account email we return, and the role/permission requirements we need.
Sources can’t be deleted while their backing agent has non-terminal media buys (ACTIVE, PAUSED, PENDING_APPROVAL, or INPUT_REQUIRED). Cancel or terminate those first.
3

Set up billing (conditional)

Stripe Connect lets Scope3 settle payments on your behalf. Whether billing is required depends on your connected agents’ capabilities:
  • Optional when no connected source advertises agent billing. Your Storefront can go live without Stripe Connect, but it is limited to external agreements with buyers (see warning below).
  • Required when at least one connected agent advertises agent in accounts.supported_billing. Buyers can ask Scope3 to clear payments through that agent, so Stripe Connect must be configured before activation. The readiness check billing_setup returns isBlocker: true until onboarding completes.
If billing is optional and you skip it, your Storefront will be limited to external agreements with buyers. Scope3 will not support payment clearing for inventory sold through this Storefront, and the seller is responsible for billing the buyer directly.
Child customer accounts always inherit billing from the parent and cannot provision their own.

1. Provision a Connect account

curl -X POST https://api.interchange.io/api/v2/storefront/billing/connect \
  -H "Authorization: Bearer scope3_..."
Response
{
  "stripeConnectedAccountId": "acct_1Abc...",
  "onboardingUrl": "https://connect.stripe.com/setup/e/acct_1Abc.../..."
}
Redirect the operator to onboardingUrl to complete Stripe’s KYC flow.If the operator drops out mid-onboarding, get a fresh link:
curl https://api.interchange.io/api/v2/storefront/billing/onboard \
  -H "Authorization: Bearer scope3_..."

3. Check status + balance

curl https://api.interchange.io/api/v2/storefront/billing/status \
  -H "Authorization: Bearer scope3_..."
Response
{
  "accountId": "acct_1Abc...",
  "chargesEnabled": true,
  "payoutsEnabled": true,
  "requirements": {
    "currentlyDue": [],
    "eventuallyDue": ["external_account"]
  },
  "balance": {
    "available": [{ "amount": 4250000, "currency": "usd" }],
    "pending": [{ "amount": 120000, "currency": "usd" }]
  }
}

Other billing endpoints

EndpointPurpose
GET /api/v2/storefront/billingCurrent platform fee %, additional fees, currency, net days
PUT /api/v2/storefront/billingAdmin-only — update fee config
GET /api/v2/storefront/billing/transactionsCursor-paginated balance transactions
GET /api/v2/storefront/billing/payoutsCursor-paginated payouts
POST /api/v2/storefront/billing/account-sessionEmbedded Stripe Connect session for in-app onboarding UI
GET /api/v2/storefront/billing/accountsParent customers — billing status across child accounts
Parent customers can pass ?targetCustomerId=<childId> on every /api/v2/storefront/billing/* endpoint to operate on a child’s billing. Access is validated against the parent/child relationship before each call.
4

Go live

Activation flips the storefront from PENDING to ACTIVE. Buyer agents can only transact against your inventory once you’re live. Public marketplace discovery has one additional human-review gate: newly live Storefronts remain pending marketplace review until a Scope3 admin lists them.

1. Confirm readiness

GET /api/v2/storefront/readiness runs every gate that activation will check server-side. Call it any time during onboarding to see what’s still missing.
curl https://api.interchange.io/api/v2/storefront/readiness \
  -H "Authorization: Bearer scope3_..."
Response
{
  "platformId": "acme-media",
  "status": "ready",
  "checks": [
    {
      "id": "inventory_sources",
      "name": "Inventory sources",
      "category": "inventory",
      "description": "At least one source has been configured.",
      "status": "complete",
      "isBlocker": true,
      "method": "agent",
      "details": "1 source configured"
    },
    {
      "id": "agent_status",
      "name": "Agent status",
      "category": "agents",
      "description": "All agents are active.",
      "status": "complete",
      "isBlocker": true,
      "details": "1 of 1 agents are active"
    },
    {
      "id": "agent_auth",
      "name": "Agent authentication",
      "category": "agents",
      "description": "All agents have been authenticated.",
      "status": "complete",
      "isBlocker": true,
      "details": "1 of 1 agents are authenticated"
    },
    {
      "id": "billing_setup",
      "name": "Billing",
      "category": "billing",
      "description": "Stripe Connect onboarding complete.",
      "status": "complete",
      "isBlocker": false,
      "details": "Stripe Connect is complete"
    }
  ]
}
  • inventory_sources (blocker) — at least one source must be connected. Buyer-facing get_products still requires at least one active source: composition storefronts need active ingredient sources, and passthrough storefronts need an active source to proxy.
  • agent_status (blocker) — every agent backing a source must be ACTIVE and have AAO compliance status passing. Sources connected with a non-passing agent will keep this check in partial until compliance flips.
  • agent_auth (blocker) — non-OAuth agents must have a stored credential. OAuth agents are excluded once their token is captured.
  • agent_connectivity (blocker, only on GET /readiness/compliance) — runs the AdCP comply() test suite against each agent in sandbox mode (60s timeout). Returns per-agent track results and observations.
  • billing_setup (conditional blocker) — Stripe is optional when no connected agent advertises agent billing in its capabilities; the check returns status: optional/partial with isBlocker: false and the external-agreements warning. Stripe becomes required once any connected agent declares agent in accounts.supported_billing; the check then returns status: missing/partial with isBlocker: true until Stripe onboarding completes. In non-production environments the check short-circuits to optional regardless of Stripe state so dev storefronts can go live without Stripe.
Top-level status is blocked if any check with isBlocker: true is not complete, otherwise ready. A check with status: optional is treated as not required.For a deeper agent connectivity test (full AdCP compliance scenarios in sandbox mode), hit:
curl https://api.interchange.io/api/v2/storefront/readiness/compliance \
  -H "Authorization: Bearer scope3_..."
This may take up to 60 seconds.

2. Activate

curl -X PUT https://api.interchange.io/api/v2/storefront \
  -H "Authorization: Bearer scope3_..." \
  -H "Content-Type: application/json" \
  -d '{ "status": "ACTIVE" }'
The API re-runs readiness server-side before applying the change. If any blocker is still failing, the request is rejected with the failing check descriptions:
Rejection
{
  "error": "VALIDATION_ERROR",
  "message": "Cannot activate storefront: All agents must be active to go live; All agents must be authenticated to go live",
  "field": "status"
}
When activation succeeds, every agent in PENDING status that’s linked through a source is automatically promoted to ACTIVE so buyer traffic can route through it. Scope3 is notified that the Storefront is ready for marketplace review.

3. Marketplace review

The marketplace review state is independent from the status lifecycle:
Marketplace stateMeaning
PENDING_REVIEWDefault for new Storefronts. The owning organization can configure and use the Storefront, but it is not shown in public buyer discovery.
LISTEDReviewed and visible in public buyer discovery and marketplace browsing, subject to the normal live/source/credential gates.
HIDDENIntentionally removed from public buyer discovery, commonly for test, internal, or deprecated Storefronts.
Scope3 reviews newly live Storefronts before listing them. This keeps test Storefronts and unreviewed sellers out of the broader marketplace without blocking the operator’s own setup work.

Lifecycle states

StatusMeaning
PENDINGCreated but not live. Buyer-side discovery does not surface it.
ACTIVELive. Buyer agents can transact; public discovery also requires marketplace review and listing.
DISABLEDTemporarily off. Existing media buys remain bound but new ones can’t be placed.
Allowed transitions: PENDING ↔ ACTIVE ↔ DISABLED (you can’t go straight from DISABLED to PENDING).

Troubleshooting

This is logged but not a blocker. The source is created and will auto-activate once the agent is reachable. No action required unless the status flips to not-passing.
Visit agenticadvertising.org and check the storyboard test results for your agent URL. Resolve the failing scenarios in your agent implementation, wait for the next test run, then retry source creation.
The agent’s endpointUrl doesn’t appear in the AAO registry at all. Register it through the AAO operator dashboard before retrying.
Your agent record is PENDING. Most often this means the auth credential hasn’t been verified yet. Re-submit the source with a fresh auth block, or for OAuth agents make sure the OAuth callback completed.
A non-OAuth agent has no stored credential. PUT /api/v2/storefront/inventory-sources/:sourceId with an auth block to set one.
Look at the compliance array on the failing check — each entry has per-track failureReason, summary, and observations. The most common causes are auth misconfiguration, schema drift between your agent and the AdCP spec, and agent-side timeouts beyond 60s.
Verification only runs when operatorDomain is being changed. If you set the domain before the customer’s customerDomain was registered, update operatorDomain to the same value again to trigger re-evaluation, or have a Scope3 admin verify manually.
Stripe credentials are missing on the API server. Contact Scope3 support — this is environment config, not a customer-side issue.
Your customer is a child of a parent org. Either provision billing on the parent and inherit, or have the parent call POST /api/v2/storefront/billing/connect?targetCustomerId=<your-id> on your behalf.

Adding a child storefront account

Multi-brand publishers split into a parent + child storefront accounts. A parent admin provisions the child via POST /api/v2/accounts/create-child (or “Add account” in the UI). After the child is created, the parent admin cannot accept the child’s Terms of Service on its behalf — a direct ADMIN of the child must accept. The create-child response carries two flags the UI uses to gate the experience:
{
  "data": {
    "customer": { "id": 9101, "company": "..." },
    "showTosBox": true,
    "canAcceptTos": false
  }
}
canAcceptTos: false tells the UI to suppress the ToS modal and route the parent admin to Account Settings instead. Team and Communications remain available — those routes are exempted from the ToS guard so the parent admin can invite the child’s first ADMIN and configure a support channel. Billing, single sign-on, API tokens, and archive stay locked until a direct ADMIN of the child signs in and accepts ToS.

Next steps