Cindy Zhu.
Free guides
Marketing Claude

How to let Claude run your ad campaigns through the API

Hey, it's Cindy ๐ŸŒฑ Claude holds a scoped API key and does the account work itself. I have used Google Ads and TikTok Ads as the worked examples.
btw the waitlist for AI System Club is now open! If you're keen on using AI to automate your content, video editing, job search, business or build AI agents, feel free to sign up (only if you want to hehe). Ps. the waitlist gets first dibs:)
Read this bit before anything else. This is the one Claude build where a mistake costs money instead of time. So the whole guide is arranged around three rules, and they are not optional: read only first, nothing goes live without you approving it, and the budget is capped in two separate places. Every step below is built so that a wrong API call fails harmlessly instead of quietly spending your money.
the actual jump

Copywriter versus operator

The difference is not how clever the prompt is. It is whether Claude can reach the platform. When Claude has an API connection, it can read your real numbers instead of the numbers you paste in, and it can write changes back as structured requests instead of asking you to click through a dashboard. That is the whole unlock, and it is also exactly why you scope it tightly.

Claude the copywriter

You describe the campaign, Claude writes headlines and angles, you copy them into Ads Manager and set everything up by hand. Good output, but you are still the one doing every click, and Claude is guessing at performance because it cannot see your account.

Claude the operator

Claude queries the account directly, so it argues from your real cost per conversion. It drafts the campaign as an actual API request, dry runs it, shows you the exact fields, and creates it paused for your approval. You review and enable. It reports back weekly.


before you start

What you need, and what it actually costs

An existing ad account Google Ads or TikTok Ads, already set up with billing. The API drives the account you already have, it does not create one for you.
API access, by application There is no paid tier to buy. Google grants a developer token through an application, and TikTok grants access through its developer portal. Both take a few days.
Claude, any paid plan Claude Pro is USD $20 a month billed monthly, or $17 a month on annual billing, per claude.com/pricing. Claude Code is included with Pro and Max.
Python and a terminal Only for the Google Ads route. The TikTok route can run entirely through a hosted connection with no code at all, which I cover below.
The honest cost line. The API itself is not what you pay for. Your real spend is the ad budget, and that number is entirely under your control if you set the caps in step 5. Google publishes daily operation limits per access level rather than a price: 15,000 operations a day at Basic access, 2,880 at Explorer access, and unlimited at Standard access (access levels). For one person running their own campaigns, Basic is far more than you will use.

step 1

Connect read only first, on purpose

Do not start with the ability to spend. Start with the ability to see. Google's own Ads team publishes a Model Context Protocol server that is read only by design: it exposes three tools, list_accessible_customers, search and get_resource_metadata, and none of them can change a bid, pause a campaign or create anything (googleads/google-ads-mcp). That is the safest possible way to find out whether this workflow is worth it for you.

  1. ๐Ÿ‘ฉโ€๐Ÿ’ป Install Claude Code. Follow the Claude Code docs to install it, then run claude in a folder you have made for this project. Everything below happens inside that one folder, which matters later when you write the rules file.
  2. ๐Ÿ”‘ Have your credentials ready. The Google server needs three values: your Google Cloud project ID, your Google Ads developer token, and the path to a credentials JSON file. Step 2 is how you get all three. If you do not have them yet, read on and come back.
  3. ๐Ÿ”Œ Add the server. Run the add command below in your project folder. It registers the server, passes your three values as environment variables, and runs it through pipx so nothing is installed globally.
  4. โœ… Check it connected. Run claude mcp list. A healthy server shows Connected. If it shows Failed to connect, the cause is almost always a wrong credentials path or a developer token that has not been approved yet. The MCP reference covers the rest.
claude mcp add --transport stdio google-ads \
  --env GOOGLE_PROJECT_ID=your-project-id \
  --env GOOGLE_ADS_DEVELOPER_TOKEN=your-developer-token \
  --env GOOGLE_APPLICATION_CREDENTIALS=/full/path/to/credentials.json \
  -- pipx run --spec git+https://github.com/googleads/google-ads-mcp.git google-ads-mcp

For TikTok there is an official hosted equivalent, and it needs no credentials file at all. TikTok's Agentic Hub documentation gives two endpoints and notes that the full one is the one to use with Claude, since it loads the whole toolset at connection time (TikTok for Business MCP Server).

claude mcp add --transport http tiktok-ads https://business-api.tiktok.com/open_mcp/tt-ads-mcp-flat
The TikTok server is a remote connection, so the first time you use it Claude Code will ask you to authorise in a browser. Type /mcp inside Claude Code to see the status and finish sign in. Because this one is hosted, it exposes write tools too, which is exactly why the approval gate in step 5 matters more here than on the Google side.

Once a server is connected, this is the first prompt I run. It is a pure reading exercise, and it tells you immediately whether Claude actually understands your account.

๐Ÿ”Ž read my account before touching it
You are connected to my ad account through an MCP server. For this conversation, treat yourself as read only: query freely, but do not call any tool that creates, updates or deletes anything, even if I ask you to.

Start by listing every account I have access to and telling me which one looks like the main spending account. Then for that account, pull the last 30 days of spend, impressions, clicks, conversions and cost per conversion, broken out by campaign, and show it as a table sorted by spend.

Now interpret it for me. Which campaigns are carrying this account, which ones are quietly burning budget, and which ones have too little data to judge yet? Be explicit about the sample size behind each verdict, and say when a number is too thin to act on.

Finish with the three changes you would make if you had write access, ranked by how much money each one moves. For each change, name the exact campaign, the exact field you would set, and the evidence you would want to see before you would be comfortable making it.

step 2

Get real API access

This is the part everyone underestimates. Neither platform hands out API access instantly, so start the application before you need it. Here is each one from zero.

Google Ads

  1. ๐Ÿข Use a manager account. Developer tokens are issued against a Google Ads manager account at the top of your account hierarchy, not a normal ad account. If you do not have one, create one first. Google's developer token guide walks through it.
  2. ๐Ÿ“ Apply through the API Center. In your manager account, open the API Center, accept the terms, and fill out the access form. Google wants a live company website URL and a monitored contact email, and it does read them, so a half finished site is a common rejection reason.
  3. โณ Understand the access level you are given. New tokens start restricted. Test Account access lets you call test accounts only. Explorer access allows 2,880 operations a day against production. Basic access allows 15,000 a day against both. Standard is unlimited and reserved for large tools. All four are defined on the access levels page.
  4. โ˜๏ธ Create OAuth credentials. In the Google Cloud console, create a project, enable the Google Ads API, and create an OAuth client. Google's OAuth setup page is the exact sequence, and Claude can read it with you if any screen looks unfamiliar.
  5. ๐Ÿ“ฆ Install the client library. Run python -m pip install google-ads, per the Python client library docs. This is what your scripts will use for anything the read only MCP server cannot do.
  6. ๐Ÿ—‚๏ธ Write the config file. The library reads a file called google-ads.yaml holding your developer token, client ID, client secret and refresh token, with developer_token the one field marked required (configuration guide). Keep it outside your repo and add it to .gitignore the same day you create it.

TikTok Ads

  1. ๐Ÿงพ Register a developer app. Go to the TikTok API for Business portal, create a developer account, and register an app. You get an app ID and a secret, which you exchange for an access token tied to a specific advertiser ID.
  2. ๐Ÿงช Ask for a sandbox ad account. Before touching your real advertiser ID, create a sandbox ad account, which lets you call the full API with no real spend attached (sandbox accounts). Do all of your first campaign creation here.
  3. ๐Ÿ“ฎ Learn the one endpoint that matters. Campaigns are created with a POST to /open_api/v1.3/campaign/create/, passing your access token and a body containing advertiser_id, campaign_name, objective_type, budget_mode and budget. TikTok's own SDK reference shows the exact call shape, and the create a campaign guide covers the field values.
  4. ๐Ÿ Or skip the code. If you connected the hosted MCP server in step 1, you do not need the SDK at all: TikTok's documentation states no developer credential or custom coding is required for that route. Use the SDK when you want scripts you can version and re-run, use the MCP server when you want conversation.
Do not skip the token hygiene. An ads API token is a key to your money. Store it in a .env file or your OS keychain, never in a script, never in a screenshot, never in a chat message. Set the shortest expiry the platform offers and rotate it the moment a device or contractor changes.

step 3

Practise where money cannot move

Both platforms give you a free environment where the API behaves normally but nothing serves and nothing is charged. Building your first three or four campaigns here is what turns this from a scary idea into a boring routine.

  1. ๐Ÿงช Google: make a test manager account. Test accounts appear in the Google Ads UI as cancelled accounts, they render no ads, and they produce no impressions, conversions or cost. Better still, they do not require an approved developer token, so you can start building the day you apply rather than waiting. Full behaviour on the test accounts page.
  2. โš ๏ธ Know the two test-account limits. Because nothing serves, you cannot test anything that depends on real delivery data, including bid simulations and conversion uploads. A test hierarchy also caps at 50 accounts and is deleted after a year of inactivity, so treat it as a workbench, not an archive.
  3. ๐Ÿงช TikTok: use the sandbox advertiser. Point your access token at the sandbox advertiser ID rather than your live one and run the whole create flow end to end. When it works twice in a row without you fixing anything, move to the real advertiser ID.
  4. ๐Ÿ““ Keep the transcript. Ask Claude to write every successful request body into a file as you go. Those saved bodies become your templates, and they are far more useful than remembering which field name TikTok used for budget mode.
This step is the reason the build is safe rather than reckless. By the time real money is reachable, you have already made every beginner mistake somewhere it could not cost you anything. ๐ŸŒฑ

step 4

Give Claude a spec, not a vibe

An operator with a vague brief is worse than no operator. Before any API call exists, get the whole campaign written down as a file you both work from, with the numbers that decide success stated up front. This one file is what every later prompt refers back to.

๐Ÿ“‹ write the campaign spec
Before you touch the API, I want a full campaign spec written to a file called campaign-spec.md in this folder, so we are both working from the same document.

The campaign runs on [Google Ads or TikTok Ads] for [describe the offer and the landing page URL], selling to [describe the audience] in [countries]. The hard total budget is [$X] across [N] days, with a daily cap of [$Y], and those two numbers are ceilings, not targets.

The single metric that decides whether this worked is [cost per lead, ROAS, or cost per purchase] with a target of [number]. If it goes above [ceiling number] for two consecutive days, the campaign gets paused. Write that rule into the file in plain language.

Now write out the full structure: campaign name, objective, budget mode and amount, bidding strategy, targeting, ad group structure, and the exact ad copy variants with character counts checked against the platform limits. Flag every single field where you had to guess or invent a value, in a section called "assumptions to correct", so I can fix them before anything gets created.

step 5

Dry run, then launch paused

This is the part that makes the whole thing safe, and both platforms support it properly. On Google Ads you set an optional validate_only boolean to true on a mutate request, and the API validates it exactly as if it were going to run, then skips execution and returns an empty response when there are no errors (API structure). You get every error you would have got, and none of the consequences.

๐Ÿšฆ build it as a dry run first
Using campaign-spec.md as the only source of truth, write a Python script called launch_campaign.py that creates this campaign through the platform's official client library.

The script must default to a dry run. On Google Ads that means setting validate_only to true on every mutate request, creating the campaign budget resource first, then creating the campaign that references it with status set to PAUSED. Nothing real happens unless I pass a --live flag on the command line, and even with --live the campaign is still created paused.

When it runs, print a plain English summary of exactly what would be created: campaign name, objective, budget mode, budget amount, daily cap, targeting and every ad variant. Then print the raw request body too, so I can read the actual fields rather than your description of them. Stop there and wait.

Do not hardcode any credential. Read them from the config file or environment variables, never print a token or a secret to the terminal or a log, and add the config file to .gitignore if it is not already there.

Google's own campaign documentation gives the same advice as a recommendation: set the campaign to PAUSED when creating it so the ads do not immediately serve, and set it to ENABLED once targeting is in place and the ads are ready (create campaigns). Enabling is the one action you keep for yourself.

TikTok has a trap here. The operation_status field looks like it lets you create a campaign disabled, but it is an allowlist-only feature. If you pass it without being allowlisted, TikTok ignores the field and returns no error at all, so a campaign you believed was paused is live (campaign field reference). Tell Claude to always read the campaign back after creating it, and to pause it through the /campaign/status/update/ endpoint rather than trusting the create call.

the safety net

The four spend guardrails

Cap the money twice Once on the platform, as a campaign daily budget, and once in your spec file as the number Claude is forbidden to exceed. One cap is a preference. Two caps that have to agree is a control.
Scope the token Generate the token against one advertiser or one customer ID, not your whole business account, and give it read scopes only until you genuinely need write. Shortest expiry the platform allows, rotated on any change.
Paused on create, always Every campaign is born paused, whether the platform recommends it or the endpoint has to be called separately. Enabling is a human action, and it should stay slightly annoying to do.
Approve every write Claude Code asks before running shell commands by default. Keep it that way, never run it with permissions skipped for this project, and add an explicit rule for the launch script so the prompt is impossible to miss.

You can write that last one into the project instead of relying on memory. Claude Code reads permission rules from .claude/settings.json in the project folder, and a deny rule always wins over an allow rule (configure permissions). Something like this is enough:

{
  "permissions": {
    "ask": [
      "Bash(python launch_campaign.py *)"
    ],
    "deny": [
      "Bash(python launch_campaign.py * --live *)"
    ]
  }
}

With that in place, the dry run always prompts you, and the live run is blocked outright until you consciously remove the deny rule. Then pin the behaviour rules alongside it in a CLAUDE.md, which Claude Code loads automatically at the start of every session in that folder (memory docs).

โœ๏ธ write the rules file
Write me a CLAUDE.md for this folder that hardcodes the rules we work by, because this project spends real money and I do not want to restate this every session.

The rules are: never make a create, update or delete API call without showing me the exact request body first and waiting for my explicit yes. Always dry run before a live run. Always create campaigns paused, and never enable one yourself under any circumstances. Never set a budget above the ceiling written in campaign-spec.md, and if the spec and my instruction disagree, stop and ask rather than picking one.

Add a security section: never print, echo, log or commit an access token, a refresh token or the config file, and never paste a credential into a summary.

Finish with a short table listing every script in this folder and marking each one as read only or can-spend-money, so the distinction is impossible to miss at a glance. Keep the whole file under one page, because a rules file nobody reads is a rules file nobody follows.

the payoff

The weekly operator loop

Once the campaign is live, the value is not the launch, it is the review you would otherwise keep skipping. This is the rhythm I would run: one prompt on a Monday, ten minutes of reading, and you approve or reject a written change list.

  1. ๐Ÿ“Š Claude reads the week. It pulls the numbers itself through the read only connection, so nothing depends on you exporting a CSV at the right moment.
  2. ๐Ÿ“ It proposes, it does not act. Changes go into a file with the exact fields and values, which means you are approving something specific rather than a vague suggestion.
  3. โœ… You approve line by line. Delete the lines you disagree with, then tell Claude to apply what is left as a dry run first, exactly like the launch.
  4. ๐Ÿ” The spec gets updated. Whatever you learned goes back into campaign-spec.md, so next week's review argues from the corrected numbers rather than the original guesses.
๐Ÿ“Š the Monday review
Pull the last 7 days of performance for every active campaign in this account and compare it with the 7 days before. Give me the numbers, not adjectives, and show them as a table.

For each campaign, report spend, the target metric named in campaign-spec.md, and whether it crossed the pause ceiling we wrote in that file. Say clearly which campaigns have enough data to judge and which ones do not, and do not make a recommendation on a campaign with a sample too small to support one.

Then write a change list into a file called changes-this-week.md: what to pause, what to raise, what to lower, and what to leave alone. For every proposed change, give the exact campaign, the exact API field and the exact new value, plus one line on the evidence behind it.

Do not execute any of it. I will read the file, delete the lines I disagree with, and tell you which ones to run. When I do, dry run them first and show me the validated request bodies before anything real happens.

good to know

Four things that will bite you

Access takes days, not minutes Google reviews developer token applications and it is not instant. Apply on day one, then build against test accounts while you wait, since those work without an approved token.
Read only really is read only Google's official MCP server cannot pause a campaign or change a bid, by design. If you expected it to act, that is the client library route in step 2, not a missing setting.
Operations are counted, not requests Google's daily limits count the sum of gets and mutates on a rolling 24 hour window, so a chatty analysis loop burns quota faster than you expect. Details on the quotas page.
Currency and timezone are account settings Budgets are interpreted in the account's currency and its timezone, not yours. Confirm both before your first live run, or a $50 daily cap can be a very different number than you pictured.

Proof

Google Ads MCP server, official repo (read only, three tools)
Google Ads API, obtain a developer token
Google Ads API, access levels and daily operation limits
Google Ads API, test accounts
Google Ads API, validate_only dry runs
Google Ads API, create campaigns (the PAUSED recommendation)
TikTok for Business, Agentic Hub and MCP server
TikTok API for Business, create a campaign
TikTok API for Business, sandbox accounts
TikTok Business API SDK, official repo
Claude Code, connect tools via MCP
Claude Code, configure permissions

the waitlist is now open

AI System Club is launching soon

Build AI systems with me through recorded lessons you can follow at your own pace. Join the waitlist for first access and the founding price.

btw this list gets first dibs
the moment doors open :)