View as Markdown
MCP Server

Approval model and safety controls

What Synter checks before a write reaches an ad platform, which writes wait for a person, and who that person is on each surface. A write here means anything that can start, stop, or change ad spend.

Every write passes the safety gate

Every script run, from the Synter app, REST, an SDK, the CLI, or MCP, goes through the same server-side safety gate. Each decision (allowed, changed, held, or blocked) is written to the workspace audit log. The gate does three things:

  • Blocks writes the workspace policy forbids: tools on the deny list or off the allow list, calls outside allowed operating hours, changes over the configured monetary limits, and budgets above the daily-budget ceiling. Nobody can approve past a block.
  • Creates paused. New campaigns and ads are created paused while "Enforce paused on create" is on (the default). Turning them on is a separate write.
  • Holds higher-risk writes for approval, depending on the workspace autonomy level and the surface (table below). A held write returns pending_review with an audit_id and the exact reviewed arguments. Nothing runs until it is approved.

All 9 Agent Shield governance layers are included on every tier (Solo $20/mo, Scale $500/mo, and Custom) — safety controls are never paywalled. Workspace owners and admins set the autonomy level in the Synter app under Settings → Autonomous: Off (live changes blocked), Suggest (the default), Auto (safe), or Auto (full). Under Off and Suggest, spend-increasing and high-risk writes are held for explicit approval: enabling or resuming campaigns, increasing a budget or bid above workspace thresholds, deleting or removing resources, creating campaigns, and sending ad creative to a platform. Protective updates — pausing a campaign or lowering a budget via the directional budget:decrease scope — run immediately and are logged to the immutable workspace audit trail (or can be held if strict hold mode is enabled). Auto (full) skips the approval hold for pre-authorized routines but never bypasses a hard policy block or daily spend cap.

Who approves what, by surface

SurfaceProtective actions (pause, directional budget:decrease)Held writes (default Suggest policy: budget increases, launches, enables)Who approves a held write
Synter app agent (campaign conversation)Run immediately, audited (or held in strict mode)Shown in the conversation as the exact reviewed actionThe person who asked, by replying I APPROVE in that conversation. An active owner or admin of the workspace can approve a teammate's held action with their own reply.
REST, SDKs, CLI, local stdio MCP (API key)Run immediately, audited (or held in strict mode)Held server-side and returned as HTTP 202: status: "pending_review" with audit_id on /api/v1/tools/run (or error: "APPROVAL_REQUIRED" on api.synterai.com/v1)Approved by a workspace owner/admin in the Synter app approval queue (replying I APPROVE) or via approve_campaign_plan with an approver-scoped token.
Hosted MCP (OAuth or X-Synter-Key)Run immediately, audited (or held in strict mode)Held server-side with status: "pending_review" and audit_id under the default Suggest policy; new campaigns are enforced PAUSED on create and all workspace daily spend caps and policy blocks applyApproved via the workspace approval queue, approve_campaign_plan, or your MCP client's interactive confirmation flow when pre-authorized by workspace policy.
Background autonomous agentsGoverned by the approval mode in Settings → Autonomous. The default, "Ask before acting", holds changes to your ad accounts for approval; read-only work and low-risk housekeeping run on their own. Draft, Auto, and Fully autonomous loosen this step by step; workspace limits and blocks still apply.

Dry-run previews and read-only safety

Every write tool supports dry_run: true (0 credits / $0.00) to preview exact platform payloads and policy validation before mutating live ad spend. You can also run the stdio MCP server with --read-only to block all write mutations at the protocol layer.

Your MCP client's confirmation

Synter marks every write tool with the MCP destructiveHint annotation alongside server-side Agent Shield enforcement. Spend-changing tools such as execute_campaign_plan and update_campaign_budget support dry_run: true (free, $0.00) so the agent can preview the exact mutation and policy evaluation before executing, and instruct the agent to confirm the account, amount, and campaign with you before calling. Keep client tool confirmation enabled for defense-in-depth alongside server-side spend caps and approval holds, or set the workspace autonomy level to Off for a strictly read-only workspace.

Campaign launches: plan → approve → execute

  1. create_campaign_plan builds the launch plan. Pass a plan_key for idempotency; the response carries the execute_token.
  2. run_launch_preflight checks conversion tracking and the landing page at plan time (read-only). get_launch_gate_policy reads whether a failing Plan QA review blocks launch in this workspace.
  3. publish_plan_document moves the plan to review. A person approves it from the share link, or the agent calls approve_campaign_plan after you have seen the plan. That call requires the expected_version you saw, so a plan edited in between is not approved unseen. It is recorded under the account that owns the key or OAuth session.
  4. execute_campaign_plan activates the entities in dependency order. If a step fails, entities it already activated are paused (best effort). get_plan_execution reports per-entity results.

In production, execution refuses a plan that is not approved, and qa_override_approved defaults to false. On staging (rollout note above), executing through an API key or MCP approves a draft or in-review plan automatically, with a review row recorded as "MCP Operator", and qa_override_approved defaults to true. Launching from the Synter app still requires an approved plan.

Pausing

Pausing is a routine update. It runs without an approval step on every surface under the default policy and is audited. Through REST, POST /v1/campaigns/{id}/pause pauses child ad sets or ad groups too on Meta, Microsoft, Reddit, TikTok, and X. Turning a campaign back on is an enable, which is held under Off and Suggest. A campaign guardrail (below) can pause a Google Ads campaign for you.

Ongoing controls

  • Campaign guardrails (Google Ads only): set_campaign_guardrail arms an automatic pause for one campaign once it passes a minimum age and spend threshold with zero conversions on a verified conversion action. Setting it up counts as standing approval for that pause. list_campaign_guardrails shows state; disable_campaign_guardrail turns the rule off without changing the campaign.
  • Spend alerts: set_spend_alert notifies by email, Slack, SMS, or WhatsApp when weekly spend passes a threshold. It alerts; it does not pause anything.

After a change: verify

  • get_ad_readback reads a launched ad back from the platform API and checks the CTA and copy. Supported for Meta, Reddit, LinkedIn, and Google Ads; other platforms return a labeled unsupported result.
  • get_account_changelog returns the Google Ads change history (the platform API caps it at 30 days). Other platforms report changelog_supported: false.
  • get_spend_reconciliation compares Google Ads and The Trade Desk totals for up to 92 days (read-only).

Pending writes over REST

On https://api.synterai.com/v1, a held or blocked write returns HTTP 202. safety_gate_action tells you which: pending is waiting for approval; block was refused by policy. Credits are only deducted when a write succeeds.

json
{
  "success": false,
  "error": "APPROVAL_REQUIRED",
  "safety_gate_action": "pending",
  "audit_id": "3f0c…",
  "reviewed_args": ["--campaign-id", "1234567890", "--action", "enable"]
}
  • GET /v1/tools/pending lists held writes for the key's workspace.
  • POST /v1/tools/approve/{audit_id} and POST /v1/tools/reject/{audit_id} (alias DELETE /v1/tools/pending/{audit_id}) need the caller to be a workspace owner or admin and a review saved by the Synter app when that person replied I APPROVE. With an API key alone they return 409 review_required_or_changed (403 for non-admins). Approve in the Synter app instead.

Related: scopes (a key without a write scope cannot write at all), Pause Campaign, Update Budget, errors.

Was this page helpful?