Paid-media campaign lifecycle
Erdo can read a connected ad account in full — campaigns, spend, status, keywords — and it can also act on a campaign: pause it, enable it, or change its daily budget. The lifecycle endpoints expose exactly those three actions over/v1 (and the matching MCP tools), so an external product or script can
drive a decision the evidence argues for instead of someone performing it by
hand in the provider’s console.
Every lifecycle call goes through the same approval gate that governs
agent-proposed changes. There is one gated path into a customer’s ad account,
not two: the /v1 call files the very action an agent’s tool would file — same
action key, same input, same deduplication — and a caller with an API key is
never more trusted than an agent.
Supported providers: google_ads. Any other provider is rejected with an
unimplemented error rather than silently ignored.
For new campaigns, see Search campaign setup, including
the Google Search-only network default and the checks before launch.
The two outcomes
What happens depends on whether your organization has granted a standing always-approve policy for the action (the same standing grant you create by choosing “always allow” when deciding an agent’s approval):-
No standing policy — propose. The call does not touch the provider.
It files a pending approval request and returns
status: "pending_approval"with theapproval_request_id— accepted, not performed (202 semantics, expressed in the body). The approval appears in the activity feed and onGET /v1/approvals, stamped withsubject_resource_type: "paid_media_campaign"and the campaign’s external id so you can list everything awaiting decision about one campaign. When a human approves it — feed, CLI, orPOST /v1/approvals/{id}/decide— the exact stored action executes, under the approver’s identity. A rejection is terminal and nothing reaches the provider. -
A recent reasoned rejection — declined. If a person declined this same
change with a reason in the last seven days, and your request states no new
reason, the call files nothing and returnsstatus: "declined"with adeclineobject: the rejectedapproval_request_id,decided_at, the person’sreason, and who decided. There is no pending approval to wait on; stop proposing it until the hold passes, or re-propose with areasonthat says what changed. See Declining with a reason. -
Standing policy — execute. The call executes immediately through the same
integration handler an agent-run approval would execute, and returns
status: "executed"with the provider’s result.
Read and scope campaign conversion goals
Two surfaces cover a campaign’s conversion goals — the goals a campaign optimizes toward:id, name, status,
bidding_strategy_type, and goal_config_level (CUSTOMER when the campaign
follows the account’s goals, CAMPAIGN when it carries its own custom goal);
a campaign-level campaign also carries conversion_actions — the custom
goal’s conversion action ids and names. The conversion_actions top-level
list holds the owned conversion actions with id, name, type, category,
and primary_for_goal. An omitted customer_id uses the account selected on
the Google Ads connection.
The write pins one campaign’s custom conversion goal to exactly the listed
conversion action ids and disables the campaign’s inherited account goals, so
the campaign optimizes toward its own form submits and qualified-lead uploads
only:
scope_google_ads_campaign_conversion_goals
action the agent files, with the same campaign and conversion-action ownership
checks. Without a standing always-approve policy it returns
status: "pending_approval" with an approval_request_id; with one it
executes and returns status: "ready" with the resulting goal. When the
campaign’s custom goal already equals the requested set it answers ready
and writes nothing — no approval, no provider call. It never changes
campaign status or bidding.
The CLI equivalents are erdo paid-media campaigns list and
erdo paid-media campaigns conversion-goals <campaign_id> --actions 111,222.
Set campaign status
externalID(path) — the provider’s campaign id.provider—google_ads.customer_id— the provider account the campaign belongs to (campaign ids are only unique within an account). Required.status—pausedorenabled. Removal is deliberately not exposed: deleting a campaign is destructive, not lifecycle.reason(optional) — shown on the approval card as the why beside the what, so the approver reads the evidence, not just the action.
Set campaign daily budget
daily_budget_micros— the new daily budget in micros of the account currency (50000000= $50.00). Must be positive.
Response
Following up on a pending action
List what is awaiting decision about one campaign:always_org, with parameter constraints)
creates the standing policy that makes subsequent identical calls execute
immediately — see Approvals and Autonomy.
Before proposing another ad, the campaign review checks your existing copy,
approved price or budget band, and the action the destination actually offers.
An ad leading to a request form should invite a request. It should not promise
published plans or an immediate download unless the destination provides them.
Shared research can suggest a local test; its outcome must be measured using
your own traffic and leads. Adding a second ad is not a randomized A/B test.
What a new campaign starts with
When Erdo builds a paid-search campaign for you it does not start from a blank sheet. Two things go in before the first click is bought — one of them learned about your kind of business, the other read from your own account:- Exclusions. A library of search terms a business in your vertical should never pay for — someone looking to rent when you are selling, someone price-fishing well below your offer, someone searching a different product class entirely. It is grouped by vertical and by language, so a campaign running Spanish and Portuguese angles gets the Spanish and Portuguese exclusions too: a new-development condo tower selling in Miami excludes rental intent in all three languages from day one, because that is the single biggest source of wasted clicks in that market. These are on top of, not instead of, what your own campaigns have already learned — a new campaign inherits the exclusions your existing campaigns already carry. Once it is running, the traffic quality monitor tells you when off-offer traffic is climbing, and the exclusions that answer it are proposed for your approval like any other change to your account.
- Cost expectations, taken from your own account. A new campaign may use an expected conversion rate as planning evidence. Erdo establishes that from your history — your other campaigns matched on the same offer, audience geography and language, and the leads they actually produced — and says in the plan which campaigns it read, the numerator and denominator, the date window and the uncertainty. Where you have no comparable history, it labels the planning assumption rather than presenting it as a measurement. Thirty observed conversions may be an internal benchmark-review trigger only; it is not a Google requirement, learning guarantee or statistical sufficiency claim. The review also considers Google’s actual strategy status, conversion delay/cycles and an agreed measurement window. See Google’s learning guidance, conversion-based bidding and evaluation guidance.
Conversion checks before serving
Enabling a campaign, ad group, ad or keyword checks the primary destinations that would become eligible to serve. Creating an enabled ad or keyword and editing its desktop or mobile URL use the same check. Paused drafts are checked when their parent campaign or ad group is enabled. A new campaign with no ads can be enabled; its first enabled ad must pass the destination check. Account mutations are serialized through the provider response so a concurrent parent enable and child creation cannot both validate an older paused state. A busy account returns a retryable error before any provider write. For a published Erdo page, the check reads its served scripts and every current experiment variant. An installed browser conversion placeholder, a foreign or removed conversion target, or a missing website target selected by the campaign refuses the provider mutation. The error identifies the campaign, page and configuration problem. An unavailable provider or page read also refuses the mutation. Organic publication remains available with an unfilled placeholder. Sitelinks are paid-click destinations too. Linking a sitelink to a published Erdo page whose conversion is still the unfilled placeholder is refused while the campaign is enabled, and enabling a campaign is refused while any of its sitelinks, or the account’s, still lands on such a page. Unlike the ad and keyword check, a sitelink page or link that cannot be read does not block the change; only a page known to carry the placeholder does. Script inspection follows conversion calls and the landing kit’s conversion configuration. An unused object is not proof of installation. Shadowed or reassigned runtime globals, escaping configurations and unsupported dynamic conversion targets remain unresolved and refuse activation. A helper’s literal event name is resolved only when every reference is a direct call with the same string argument. Standard Google queue bootstraps and closed helpers that forward untouched arguments are supported. Aliased conversion functions and mutated configuration arrays remain unresolved. The connected account’s actions and campaign goals determine whether a browser tag is required. Explicit offline-upload goals can operate without one. The check changes no conversion action, goal, bidding setting or page. Campaign goal scoping leaves campaign status unchanged; campaign enabling remains a separate operation that performs the destination check. Direct goal mutations recheck under the same account owner that each affected campaign is paused, or is serving on click or manual bidding, which ignores conversion goals. The scoping operation skips that recheck for its own goal writes while keeping the account lock, tenancy checks and ownership checks; neither path changes campaign status. External destinations returnunverifiable_external in conversion_tracking_checks;
this check cannot establish their conversion configuration. A successful
configuration check does not prove that a visitor’s conversion was delivered
or attributed by Google.
MCP tools
The same capability is available as MCP tools:erdo_set_paid_media_campaign_status— provider, customer id, campaign id,paused/enabled, optional reason.erdo_set_paid_media_campaign_budget— provider, customer id, campaign id, daily budget in micros, optional reason.erdo_ensure_paid_media_conversion_action— exact action name, optional Google Ads customer id, and optional lead category. It reuses an enabled exact-name conversion action or requests approval to create anUPLOAD_CLICKSaction withONE_PER_CLICKcounting andprimary_for_goaldisabled. An omitted customer id uses the selected operating account.
--category SUBMIT_LEAD_FORM to classify form submissions, or
--customer-id 1234567890 to target another account this Google Ads connection
is authorized to operate. A ready result includes the conversion action id. If
creation needs a human decision, the command returns pending_approval and the
approval request id; the action is created after approval.
Bidding is not on this surface. How a campaign bids — and, in particular, which
of an organization’s campaigns share a bidding strategy so their conversions pool
— is decided when the campaign is created or promoted, through approval cards
rather than a lifecycle call. See How Erdo bids.
Erdo’s campaign-write boundary is server-side: new campaigns and bidding updates
must use conversion bidding, and an enable reads the campaign’s effective
provider strategy first. A legacy campaign that reads as click or manual bidding,
or whose strategy cannot be identified, is refused before the status write;
PAUSED remains available for management. Existing campaigns are still reported
by the read and monitoring surfaces so they can be reviewed and promoted through
the approval path. Maximize Conversions does not require an arbitrary 15- or
30-conversion minimum; review the provider’s actual history, delay and strategy
status instead.
Conversion-goal scoping holds the same account mutation ownership from the
initial campaign status read through the custom-goal configuration and
inherited-goal disable writes. A concurrent account mutation through this
platform is refused until that sequence finishes. Campaign creation holds the
same ownership through organization binding, conversion scoping and any
explicitly requested final enable; external Google UI or API writers do not
participate in this lock. The operation remains bounded and never pauses or
enables the existing campaign. A provider timeout can still leave a goal write’s
outcome unknown, but campaign status remains unchanged.
A serving campaign therefore keeps serving while its goal is isolated,
regardless of bidding strategy. The approval card and result both state that
status is unchanged. Scoping can briefly expose the additive goal state between
its two writes; that bounded window is preferred to silently stranding a serving
campaign in PAUSED. Retry the same idempotent scoping operation after a partial
or unconfirmed goal write. No follow-up re-enable is needed.
Changing website conversion actions while ads serve
Website conversion-action creation, updates and removal are checked against the connected account’s current campaign goals and serving primary destinations before the provider write. A newly effective website action must already be installed on each affected owned public page; an installed target cannot be removed while its page is serving. New actions have no provider-generated label before creation, so use an explicit secondary action for setup or complete setup while the affected campaigns are paused. The platform never pauses campaigns or changes a primary setting as a side effect of this check. The check preserves customer and campaign goal modes, including custom-selected secondary actions and explicit offline conversion modes. Actual category/origin goal rows take precedence; newly created website goal combinations follow Google’s documented category inheritance. An unrelated foreign campaign does not block an action change, but an affected foreign managed destination cannot be verified and refuses the write without reading its private content. External primary destinations remain explicitly unverifiable. These checks establish configuration compatibility, not successful conversion delivery or attribution.Supported serving channels
Conversion-integrity checks currently model Google AdsSEARCH campaigns,
including desktop, mobile and keyword destinations. An enabled campaign in an
unsupported or unknown channel is retained in the authoritative campaign
inventory even when it has no ad groups. Enabling that campaign, requesting a new
unsupported campaign as enabled, or making a relevant conversion-action change
that affects such a campaign’s effective goals or may invalidate an installed
secondary website tag returns a visible error before the requested provider
mutation. Authoritatively unrelated goal changes and unchanged enabled secondary
actions do not require that unsupported destination model. PERFORMANCE_MAX asset-group destinations are not modeled;
an empty ad-group result does not establish that a campaign cannot serve.
Paused campaign setup remains available. The platform does not pause campaigns,
change URL expansion, or change primary conversion settings to satisfy this
check. New website actions keep Google’s primary default unless explicitly set;
setup that needs a secondary action must pass
extra_params: {"primaryForGoal": false} and bind its campaign’s explicit goal
while paused. These checks establish supported configuration compatibility,
not successful conversion delivery.
Search destination checks also read the authoritative ad type and campaign asset
automation settings. Prospective serving Dynamic Search Ads
(EXPANDED_DYNAMIC_SEARCH_AD) and opted-in
FINAL_URL_EXPANSION_TEXT_ASSET_AUTOMATION are refused because their effective
landing URLs cannot be established from the configured ad URLs. AI Max search-term
matching alone remains supported with a fixed primary destination. Paused ads,
paused ancestors and campaigns without enabled ads retain their setup behavior.
A serving ad needs a primary desktop destination. A responsive Search ad with no
ad-level URL can use keyword-only destinations only when every enabled positive
criterion is authoritatively a keyword with a fixed primary URL and no keywordless
AI Max path exists. Mobile URLs alone do not prove the primary destination.
Relevant campaign settings edits are checked against their prospective status
and automation values, including fields forwarded through extra_params.
Wildcard update masks are refused visibly; name the fields being changed.
Authoritatively unrelated action mutations retain the structured
unverifiable_dynamic_destination_unaffected_goal limitation rather than claiming
all dynamic destinations were verified. No expansion or campaign setting is
changed automatically.
Google documents Dynamic Search Ad serving URLs
and AI Max asset automation defaults.
Conversion-action checks read and project the account action inventory once per
request and batch campaign goal configurations and custom goals. Every enabled
campaign remains in the check, including accounts whose inventory spans multiple
batches. Missing, duplicate or unexpected goal owners fail visibly instead of
using another campaign’s configuration. The snapshot is not retained across
requests.
