---
title: "Submit Suggested Changes"
method: POST
path: "/agent/cli/submit_suggested_changes"
---

# Submit Suggested Changes

`POST /agent/cli/submit_suggested_changes`

Persist a plan emitted by the agent.

Each call creates a new plan and supersedes the ACTIVE plan in the same
supersede scope, of which there is at most one:

* In case of a routine run, the scope is the routine, so a later fire
  replaces what an earlier fire left pending (even if the plan is in a
  different session).
* In case of a manual chat, the scope is that session alone — it can never
  withdraw a routine's pending plan.

`version` does not follow the scope: it counts resubmissions within one
session. See `plan.repository.create_plan`.

The plan id we return is server-generated and stable; the agent's own
`Plan.id` is intentionally not used as an idempotency key (the agent isn't
trusted to mint stable ids, and a duplicate-content row is harmless).

## Request body

- PlanInput
  - `id` string, required
  - `title` string, nullable
  - `estimated_impact` string[], required
  - `suggestions` SuggestionInput[], required
    - `id` string, required
    - `action` 'scale-up' | 'scale-down' | 'pause' | 'activate' | 'bid' | 'rename' | 'duplicate-ad' | 'duplicate-adset' | 'duplicate-campaign', required
    - `platform` 'meta', required
    - `primary_target` ChangeTarget, required
      - `scope` 'campaign' | 'adset' | 'ad', required
      - `platform_object_id` string, required
      - `name` string, required
      - `campaign_id` string, nullable
      - `campaign_name` string, nullable
      - `adset_id` string, nullable
      - `adset_name` string, nullable
    - `summary` string, required
    - `rationale` string, required
    - `reasons` Evidence[], required
      - `text` string, required
      - `polarity` 'positive' | 'negative', required
    - `confidence` number, required
    - `impact` number, required
    - `viz` Viz, required — How the FE should render data behind a Suggestion. The agent declares *which* metrics to query and *how* (date range, granularity, attribution); the FE issues the insight query and renders cards/sparkline from the result. The agent never embeds pre-computed values.
      - `primary_metric` union, required
        - EventMetricSpec
          - `slug` string, required
          - `type` 'events' | 'revenue' | 'cpa' | 'roas' | 'acos' | 'sessions' | 'session_conversion_rate' | 'session_duration' | 'new_visitor_sessions' | 'new_visitor_sessions_rate' | 'avg_session_revenue' | 'bounce_rate', required
          - `event_name` string
          - `label` string, nullable
        - MarketingMetricSpec
          - `slug` string, required
          - `type` 'spend' | 'clicks' | 'impressions' | 'cpc' | 'cpm' | 'ctr' | 'ad_conversions' | 'ad_revenue' | 'ad_roas' | 'ad_cpa' | 'ad_acos' | 'northbeam_nv_rate', required
          - `conversion_name` string
          - `label` string, nullable
      - `supporting_metrics` union[]
        - union
          - EventMetricSpec
            - `slug` string, required
            - `type` 'events' | 'revenue' | 'cpa' | 'roas' | 'acos' | 'sessions' | 'session_conversion_rate' | 'session_duration' | 'new_visitor_sessions' | 'new_visitor_sessions_rate' | 'avg_session_revenue' | 'bounce_rate', required
            - `event_name` string
            - `label` string, nullable
          - MarketingMetricSpec
            - `slug` string, required
            - `type` 'spend' | 'clicks' | 'impressions' | 'cpc' | 'cpm' | 'ctr' | 'ad_conversions' | 'ad_revenue' | 'ad_roas' | 'ad_cpa' | 'ad_acos' | 'northbeam_nv_rate', required
            - `conversion_name` string
            - `label` string, nullable
      - `since` string, date, required
      - `until` string, date, required
      - `time_granularity` 'hour' | 'day' | 'week' | 'month', required
      - `attribution` ConvergeApiPlanSchemaAttribution
        - `model` 'direct_session' | 'first_touch' | 'first_touch_paid' | 'inv_j_shaped' | 'inv_j_shaped_paid' | 'j_shaped' | 'j_shaped_paid' | 'last_touch' | 'last_touch_paid' | 'linear' | 'top_of_funnel' | 'participation' | 'u_shaped' | 'time_decay' | 'inv_time_decay', required
        - `window` integer, required
        - `mode` 'click_time' | 'conversion_time', required
    - `changes` union[], required
      - union
        - DailyBudgetChange
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `from_amount` number, required
          - `to_amount` number, required
          - `currency` string, required
          - `scope` 'campaign' | 'adset', required
          - `field` 'daily_budget', required
        - LifetimeBudgetChange
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `from_amount` number, required
          - `to_amount` number, required
          - `currency` string, required
          - `scope` 'campaign' | 'adset', required
          - `field` 'lifetime_budget', required
        - DailySpendCapChange
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `from_amount` number, required
          - `to_amount` number, required
          - `currency` string, required
          - `field` 'daily_spend_cap', required
          - `scope` 'adset', required
        - LifetimeSpendCapChange
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `from_amount` number, required
          - `to_amount` number, required
          - `currency` string, required
          - `field` 'lifetime_spend_cap', required
          - `scope` 'campaign' | 'adset', required
        - BidAmountChange — Ad set bid/cost goal (`bid_amount`), in the account's major units. Backs Meta's `LOWEST_COST_WITH_BID_CAP` (bid cap) and `COST_CAP` (cost-per-result goal) bid strategies — both store their target in the ad-set-level `bid_amount` field, so a single change variant covers both.
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `from_amount` number, required
          - `to_amount` number, required
          - `currency` string, required
          - `field` 'bid_amount', required
          - `scope` 'adset', required
        - RoasGoalChange — Ad set minimum-ROAS goal for the `LOWEST_COST_WITH_MIN_ROAS` strategy.
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `field` 'roas_average_floor', required
          - `scope` 'adset', required
          - `from_roas` number, required
          - `to_roas` number, required
        - StatusChange
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `field` 'status', required
          - `scope` 'campaign' | 'adset' | 'ad', required
          - `from` 'ACTIVE' | 'PAUSED', required
          - `to` 'ACTIVE' | 'PAUSED', required
        - NameChange
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `field` 'name', required
          - `scope` 'campaign' | 'adset' | 'ad', required
          - `name` string, required
        - DuplicateAdChange — Duplicate an existing ad into another adset reusing the source ad's creative
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `field` 'duplicate_ad', required
          - `scope` 'ad', required
          - `destination_adset_id` string, nullable
          - `status_option` 'ACTIVE' | 'PAUSED' | 'INHERITED_FROM_SOURCE'
          - `rename_suffix` string, nullable
          - `rename_prefix` string, nullable
        - DuplicateAdsetChange — Duplicate an existing ad set — its settings and its ads. Applied by *recreating* the ad set (Meta's `/copies` can only name the copy via prefix/suffix, and name-based URL parameters freeze at first publish, so the copy must be created bearing its final name). The child ads are then duplicated into the copy reusing each source ad's creative, so post IDs carry over; the ads keep their source names and statuses.
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `field` 'duplicate_adset', required
          - `scope` 'adset', required
          - `destination_campaign_id` string, nullable
          - `status_option` 'ACTIVE' | 'PAUSED' | 'INHERITED_FROM_SOURCE'
          - `rename_suffix` string, nullable
          - `rename_prefix` string, nullable
          - `budget` Budget — A monetary amount with its spend period.
            - `amount` number, required
            - `currency` string, required
            - `period` 'daily' | 'lifetime', required
          - `bid` MonetaryAmount — A currency-denominated value — major units on the wire, the ad account's currency, scaled to minor units at the Meta boundary.
            - `amount` number, required
            - `currency` string, required
          - `attribution` AttributionSetting — A Meta attribution setting, as the human-facing window pair. Translated to the ad-set-level `attribution_spec` at the applier boundary (`converge_api.plan.facebook.attribution_setting_to_spec`). Meta's valid combinations today: 1- or 7-day click, optionally with a 1-day engaged view (video) and/or a 1-day view.
            - `click_window_days` 1 | 7, required
            - `engaged_view_window_days` 0 | 1
            - `view_window_days` 0 | 1
        - DuplicateCampaignChange — Duplicate an existing campaign — its settings, ad sets, and ads. Applied by *recreating* the whole tree (see `DuplicateAdsetChange` for why `/copies` can't be used): the campaign is created bearing its final name, each ad set is recreated into it keeping its own name and status, and each ad is duplicated reusing the source ad's creative so post IDs carry over.
          - `target` ChangeTarget, required
            - `scope` 'campaign' | 'adset' | 'ad', required
            - `platform_object_id` string, required
            - `name` string, required
            - `campaign_id` string, nullable
            - `campaign_name` string, nullable
            - `adset_id` string, nullable
            - `adset_name` string, nullable
          - `note` string, nullable
          - `field` 'duplicate_campaign', required
          - `scope` 'campaign', required
          - `status_option` 'ACTIVE' | 'PAUSED' | 'INHERITED_FROM_SOURCE'
          - `rename_suffix` string, nullable
          - `rename_prefix` string, nullable
          - `attribution` AttributionSetting — A Meta attribution setting, as the human-facing window pair. Translated to the ad-set-level `attribution_spec` at the applier boundary (`converge_api.plan.facebook.attribution_setting_to_spec`). Meta's valid combinations today: 1- or 7-day click, optionally with a 1-day engaged view (video) and/or a 1-day view.
            - `click_window_days` 1 | 7, required
            - `engaged_view_window_days` 0 | 1
            - `view_window_days` 0 | 1

## Response `200`

Successful Response

- SubmitSuggestedChangesResponse — What `./converge submit-plan` prints back to the agent. The agent surfaces `plan_id` as the input to its `submit_suggested_changes` custom tool; the FE fetches the persisted plan body via `GET /api/plans/{plan_id}`.
  - `plan_id` integer, required
  - `version` integer, required
  - `superseded_plan_id` integer, nullable

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/runconverge/apis/fastapi.md) · [All operations](https://skmtc.dev/runconverge/apis/fastapi/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/runconverge/fastapi/revisions/1452e350bd1d/schema)
