View as Markdown
SDK

Python SDK

pip install synter — typed client for 25 catalog tools plus an execute() escape hatch for any whitelisted PPC script.

Install

bash
pip install synter

Quickstart

python
import os
from synter import Synter

client = Synter(api_key=os.environ["SYNTER_API_KEY"])  # api_key is required

campaigns = client.campaigns.list(platform="google", status="ENABLED")
perf = client.analytics.get_performance()  # default: google, LAST_7_DAYS
spend = client.analytics.get_daily_spend()  # default: google, last 7 days

Optional analytics args

get_performance and get_daily_spend accept an optional platform (default google). Empty calls are valid. They dispatch to the platform pull scripts (pull_google_ads, pull_meta_ads, …), not to get_account_daily_spend.

The client sends Authorization: Bearer syn_….

SurfaceAcceptedUse
REST tools endpointAuthorization: Bearer syn_…, X-Synter-Key: syn_…, X-API-Key: syn_…Authorization: Bearer syn_…
REST resource endpointsAuthorization: Bearer syn_…, X-Synter-Key: syn_…Authorization: Bearer syn_…
SDKs (Python, TypeScript, Rust, Java, Go) and the synter CLIThe SDK sets the header for youPass the key to the client. Every SDK sends Authorization: Bearer syn_…
Local stdio MCP (npm @synterai/mcp-server)Set SYNTER_API_KEY in the server's env blockThe package sends Authorization: Bearer syn_…
Hosted MCPBrowser OAuth (the client sends Authorization: Bearer <OAuth access token>), or X-Synter-Key: syn_… for headless clientsOAuth. Headless: X-Synter-Key. Do not put an API key in Authorization on this host.

Keys start with syn_ (sandbox keys with syn_test_). Create one at synterai.com/developer, keep it in SYNTER_API_KEY or a secret store, and send one header per request. On the hosted MCP endpoint, the Authorization header is reserved for the OAuth token the client gets from browser sign-in, so a failed key there shows up as a sign-in prompt rather than a key error. Use X-Synter-Key when you connect a hosted MCP client with a key. Details: Authentication.

Write: pause a campaign and change its daily budget

Both calls change a live Google Ads campaign. platform is required, but the request always goes to Google Ads; use the REST endpoints for other platforms.

python
import os
from synter import Synter
from synter.errors import SynterError

client = Synter(api_key=os.environ["SYNTER_API_KEY"])

paused = client.campaigns.pause(campaign_id="1234567890", platform="google")

try:
    result = client.campaigns.update_budget(
        campaign_id="1234567890", platform="google", daily_budget=75.0
    )
except SynterError as err:  # 403 = blocked by policy or missing scope
    print(err.status, err.code)
    raise

if result.get("status") == "pending_review":
    print("Held for approval, nothing ran:", result["audit_id"])

Writes the safety gate holds or refuses

With the default workspace policy, pausing a campaign and changing a budget run straight away and are recorded in the audit log. Enabling or resuming a campaign, deleting or removing anything, sending creative to a platform, and creating new campaigns can be held for approval. A held write returns HTTP 202 with status: "pending_review", an audit_id and the exact reviewed_args. Nothing has run at that point. The SDKs return this body as a normal result, so check status before you report success.

A write the policy refuses (blocked tool, outside operating hours, over a monetary limit) returns HTTP 403 with status: "blocked", and the SDKs raise their error type. Approval cannot override a block.

An API key cannot approve its own pending write. See Approval model and safety controls for who approves what and where.

Closed-Loop Readback Verification

For autonomous coding agents operating under authorized apply mode, synter >= 0.2.0provides atomic write-and-verify helpers. These mutate the campaign and immediately read back effective provider state rather than assuming success from a 2xx response:

python
# Atomic budget update with verification readback
budget_verified = client.campaigns.update_budget_and_verify(
    campaign_id="1234567890",
    daily_budget=25.0,
    platform="google",
)
print("Effective provider budget:", budget_verified["verified_state"])

# Atomic pause with verification readback
pause_verified = client.campaigns.pause_and_verify(
    campaign_id="1234567890",
    platform="google",
)
print("Effective provider status:", pause_verified["verified_state"])

Async

python
import asyncio
from synter import AsyncSynter

async def main():
    async with AsyncSynter(api_key="syn_...") as client:
        print(await client.campaigns.list(platform="google"))

asyncio.run(main())

Any script

Use execute(script_name, args) for a whitelisted PPC script. MCP tool names such as list_campaigns are not scripts — call the typed method, or GET https://api.synterai.com/v1/campaigns, instead.

python
client.execute(
    "google_ads_get_campaigns",
    {"status": "ENABLED"},
    platform="google",
)

Full hosted MCP tools: /mcp/tools. Claude Code plugin: /guides/claude-plugin.

Was this page helpful?