This page covers v2 REST endpoints. MCP tool errors follow the ADCP error
spec and
are returned in
structuredContent rather than HTTP status codes.Error envelope
Every non-success response hasdata: null and a populated error object:
Successful responses have the inverse shape:
{ "data": <result>, "error": null }. List endpoints add a meta block (see Pagination).
Throughout the Buyer and Storefront task references, the
## Response examples
show the data payload only — the inner result. On the wire it is always
wrapped in the envelope above: { "data": <payload>, "error": null }, plus a
meta block on list endpoints. Read the result from response.data.HTTP status codes
Common error codes
Domain-specific codes you may encounter on campaign, currency, and reporting endpoints:
Buyer identity and storefront account errors
Buyer operations that need a seller-side account fail closed when the buyer has no confirmed operator identity. REST returns HTTP409 with
BUYER_SETUP_REQUIRED; for a missing identity, branch on this exact structured
payload:
interchange.io as a buyer operator. Doing so
would collapse unrelated buyers into one seller-side natural-key account.
Complete Buyer Setup and retry instead. Historical media buys are not
rewritten: status, creative re-sync, update, cancellation, and delivery keep
using the seller account persisted on the buy.
A legacy buyer profile that explicitly contains the platform domain returns
the same BUYER_SETUP_REQUIRED code with details.reason: "platform_operator_not_allowed". This is observable on the same buyer
surfaces as missing_operator_identity; replace the platform domain in
Buyer Setup rather than retrying it.
The Storefront MCP surface uses the ADCP error envelope rather than the REST
envelope above. When a request supplies an opaque account_id that is not
authorized for the authenticated buyer on that storefront, it returns:
account_context_not_found, and do not retry with an
account ID discovered by another buyer. Use list_accounts as the current
buyer or complete the seller’s account-linking flow.
Buyer-actionable errors on create_media_buy, update_media_buy, sync_creatives
Buy-flow errors carry an optional buyer_reason: { code, message } sub-object on
the ADCP error envelope (AdCP 3.2 core/error.json). It classifies the failure
in a way the buyer can act on — creative-validation issues, budget/product/
permission problems — with a message that is safe to render directly (no
vendor identifiers, no internal IDs, no stack traces). When buyer_reason is
present, the envelope’s recovery (transient | correctable | terminal) is
set alongside per spec and MUST agree with the buyer_reason’s classification.
code uses the AdCP enums/error-code.json vocabulary
(BUDGET_TOO_LOW, PRODUCT_NOT_FOUND, PRODUCT_UNAVAILABLE,
PERMISSION_DENIED, ACCOUNT_SETUP_REQUIRED) or an X_{VENDOR}_{CODE}
extension (Scope3 extensions: X_SCOPE3_CREATIVE_SIZE_MISMATCH,
X_SCOPE3_CREATIVE_MISSING_CLICK_URL,
X_SCOPE3_CREATIVE_VALIDATION_FAILED_GENERIC). Receivers MUST preserve
unknown codes for forward compatibility — a newer AdCP standard code or a
seller-defined extension is passed through end-to-end.
buyer_reason may also appear on each entry of details.per_source
so a per-leg diagnosis is available when a fan-out mixed causes; each entry
carries its own recovery peer. On sync_creatives, buyer_reason +
recovery appear on each failed creative row’s errors[] entry when the
source classified the batch failure.
Prefer reading the structured buyer_reason.code for programmatic routing
(retry, mutate-and-resubmit, escalate) and use buyer_reason.message for
what to show a human.
MCP Page capability errors
Host-only Page aliases return the ADCPACCESS_DENIED tool error when their
session-bound capability is missing, expired, belongs to another Page or
session, or the requested arguments fall outside that Page’s exact allowlist.
The error is returned in MCP structuredContent, not the REST envelope.
For an expired capability, the Page caller makes one renewal attempt with the
tool associated with the same Page resource and, if renewal succeeds, retries
the unchanged operation once. If renewal fails, preserve the original denial.
Do not retry a wrong-resource or off-policy call through another Page. In
Teach, ACCESS_DENIED also prevents the Page from rejecting a
destination-owned Material candidate. Teach presents that candidate as a
handoff. A direct MCP client may record rejection with public save_material;
acceptance still goes through the candidate’s named canonical typed owner.
Validation errors
When request validation fails,code is VALIDATION_ERROR and details.issues enumerates every problem Zod found, with dotted field paths:
field is set instead:
Handling errors in client code
Retrying safely
RATE_LIMITED, INTERNAL_ERROR, SERVICE_UNAVAILABLE, and FX_RATE_UNAVAILABLE are transient — retry GETs with exponential backoff. For creation/mutation requests after a 5xx, prefer to surface the error rather than auto-retry, since duplicate-create protection isn’t enforced server-side.
VALIDATION_ERROR, NOT_FOUND, FORBIDDEN, ACCESS_DENIED, CONFLICT, and SPEND_DENOMINATION_UNRESOLVED are terminal — don’t retry until the input or state changes.
CONFLICT has two narrow automatic-retry reasons, and they are machine-readable rather than a matter of reading the message. name_creation_in_progress means another writer holds that name and has not finished. adoption_in_progress means the source-identity state is still settling: another adoption is completing or its blocker changed during classification. Retry the identical request shortly for either reason. Every other adoption reason requires a changed input or state: name_taken and name_creation_abandoned require choosing another name or archiving the blocker; adoption_abandoned means a stale creation marker never cleared (an asset row may already exist), and adoption_asset_unavailable means the finalized asset is no longer usable; adoption_name_mismatch requires using the existing creative name or renaming it separately; and source_delivery_revoked or source_deletion_requested requires uploading a new source. MCP classifies those action-required cases as correctable, not transient. Branch on details.reason, never on the message.