Skip to content

ads update: support CalloutSetting (ADD/REMOVE/SET) for managing callouts on existing ads #238

Description

@axisrow

Context

direct-cli 0.3.11 added typed flags for most TextAdUpdateBase fields via issue #202 / PR #216 (--title2, --sitelink-set-id, --vcard-id, --turbo-page-id, --display-url-path). One field from the same base type was left out: CalloutSetting — and it is the only WSDL-supported way to manage callout extensions on an existing ad.

WSDL evidence (https://api.direct.yandex.com/v5/ads?wsdl):

<!-- TextAdUpdateBase, line 777 -->
<xsd:complexType name="TextAdUpdateBase">
    <xsd:sequence>
        <xsd:element name="VCardId" type="xsd:long" .../>
        <xsd:element name="AdImageHash" type="xsd:string" .../>
        <xsd:element name="SitelinkSetId" type="xsd:long" .../>
        <xsd:element name="CalloutSetting" type="ext:AdExtensionSetting" .../>
    </xsd:sequence>
</xsd:complexType>

CalloutSetting is also present in ResponsiveAdUpdate (line 815).

AdExtensionSetting (https://soap.direct.yandex.ru/v5/adextensiontypes.xsd):

<xsd:complexType name="AdExtensionSettingItem">
    <xsd:sequence>
        <xsd:element name="AdExtensionId" type="xsd:long" minOccurs="1" maxOccurs="1"/>
        <xsd:element name="Operation"     type="general:OperationEnum" minOccurs="1" maxOccurs="1"/>
    </xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AdExtensionSetting">
    <xsd:sequence>
        <xsd:element name="AdExtensions" type="ext:AdExtensionSettingItem"
                     minOccurs="1" maxOccurs="unbounded"/>
    </xsd:sequence>
</xsd:complexType>

Operation is ADD | REMOVE | SET. SET is mutually exclusive with ADD / REMOVE in the same request.

Verified by the downstream user against live JSON API:

{
  "method": "update",
  "params": {
    "Ads": [{
      "Id": 17722952445,
      "TextAd": {
        "CalloutSetting": {
          "AdExtensions": [
            {"AdExtensionId": 19718116, "Operation": "ADD"},
            {"AdExtensionId": 19718117, "Operation": "ADD"},
            {"AdExtensionId": 19718118, "Operation": "ADD"}
          ]
        }
      }
    }]
  }
}

After the call, ads.get returns AdExtensions: [{AdExtensionId, Type: "CALLOUT"}, ...] as expected.

Current behaviour in CLI 0.3.11

direct ads update --help exposes no flag mapped to CalloutSetting. There is no way to attach / detach / replace callouts on an existing ad through CLI — the user has to bypass CLI and call the JSON API directly, which breaks the strict-WSDL-parity policy and the downstream yandex-direct-mcp-plugin's "never bypass CLI" rule.

(Issue #125 in the downstream plugin was misdiagnosed earlier as "API doesn't support this" because the wrong payload key was used (TextAd.AdExtensions instead of TextAd.CalloutSetting). The hint added in CLI 0.3.10 ("--ad-extensions is for ads add, not ads update") is good but doesn't help the user find the real way.)

Proposed flags

--callouts-add    TEXT   Comma-separated AdExtension IDs of type CALLOUT to attach (Operation=ADD)
--callouts-remove TEXT   Comma-separated AdExtension IDs to detach (Operation=REMOVE)
--callouts-set    TEXT   Comma-separated AdExtension IDs to replace the full set (Operation=SET)

Validation:

  • --callouts-set is mutually exclusive with --callouts-add / --callouts-remove in a single invocation (matches WSDL: SET cannot mix with ADD/REMOVE).
  • TEXT_AD only (matches TextAdUpdateBase); same per---type gating as existing flags.

The plugin would pass them as comma-separated lists and CLI builds the CalloutSetting.AdExtensions[] payload, splitting --callouts-add + --callouts-remove into a single array with the right Operation per item.

Scope (out)

  • VideoExtension, PriceExtension (also *UpdateItem wrappers on TextAdUpdate) — separate issue if needed. This issue is scoped to CalloutSetting, which is the most common case.
  • ResponsiveAdUpdate.CalloutSettingdirect ads update only supports TEXT_AD / TEXT_IMAGE_AD / MOBILE_APP_AD subtypes today. If responsive ads land later in CLI, the same flags would apply.

Downstream

Tracked in yandex-direct-mcp-plugin: axisrow/yandex-direct-mcp-plugin#127

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions