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.

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, these writes are held: enabling or resuming something, deleting or removing something, creating campaigns, sending ad creative to a platform, and unrecognized write scripts. Routine updates, including pausing and changing a budget, bid, or keyword, run immediately and are audited. Auto (full) skips the hold but never a block.

Who approves what, by surface

SurfacePause, budget, bid changesHeld writes (default Suggest policy)Who approves a held write
Synter app agent (campaign conversation)Run immediately, auditedShown 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, auditedReturned as HTTP 202: status: "pending_review" on /api/v1/tools/run, error: "APPROVAL_REQUIRED" on api.synterai.com/v1Not the API key. Run the action again from a campaign conversation in the Synter app, check the reviewed action, and reply I APPROVE.
Hosted MCP (OAuth or X-Synter-Key)Run immediately, auditedProduction: held, same as REST. Staging: accepted automatically (see rollout note)Production: same as REST. Staging: the authenticated MCP user is treated as having approved the call; nobody else is asked.
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.

Rollout note (as of October 7, 2026)

A change merged to staging on October 7, 2026 makes the hosted MCP server accept held writes automatically for the signed-in caller. This covers creates, enable/delete updates, creative sends, and unrecognized writes. These calls are logged with approval_basis: "mcp_auto_acceptance". New campaigns are still created paused, and blocks still apply. The same change lets plan execution through an API key or MCP approve a draft or in-review plan automatically (next section). It is not in production yet; in production today, hosted MCP writes are held exactly like REST writes. REST, the SDKs, the CLI, and the Synter app are unchanged.

Your MCP client's confirmation

Synter marks every write tool with the MCP destructiveHint annotation. Spend-changing tools such as execute_campaign_plan and update_campaign_budget also tell the agent to confirm the account, amount, and campaign with you before calling. Whether you see a prompt depends on your client and its settings: Claude Code, Cursor, and others can ask before each tool call or be set to auto-approve. That prompt runs on your machine; Synter does not enforce it. Where hosted MCP accepts held writes automatically (staging, above), your client's prompt is the only per-call confirmation. Keep it on for write tools, or set the workspace autonomy level to Off for a 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?