I was about to retarget the people who already follow my Facebook page for an upcoming campaign. Instead of clicking through Ads Manager myself, I asked Tim — my AI agent — to write a script that hits the FB Marketing API directly, so the same script could be reused for every future campaign. First request, FB threw back a flat error 2654 "Invalid Event Name". No hint where the actual problem was.

Why I Wanted Custom Audiences Built by Script in the First Place

I had a campaign coming up and I wanted to retarget people who'd already engaged with my page — followers and 30-day / 60-day engagers. Anyone who's run Facebook ads knows that retargeting an engaged audience usually converts way better than blasting cold traffic.

The "normal" way to do this is Ads Manager → Audiences → Create Custom Audience → Page → "People who like or follow your Page" → Save. Five clicks. Easy enough.

But I didn't want the normal way, because:

  • I need multiple audiences (followers, engaged 30d, engaged 60d, etc.) and I'll need the same pattern for every future campaign.
  • Clicking the same five buttons over and over isn't a process — it's a tax.
  • If I have a script once, my AI agent can just create new audiences on demand the next time I run a campaign.
  • The whole point of letting Tim run my ads is that every piece is code — not a UI a human has to click through.

So I told Tim, "Write a script that creates Custom Audiences via the FB Marketing API."

Five Minutes Later — FB Threw Error 2654 Back at Me

Tim wrote the script fast because Facebook's docs have an example for it. The script POSTed to /act_{ad_account_id}/customaudiences. First response back:

{
  "error": {
    "code": 2654,
    "message": "Invalid Event Name",
    "type": "OAuthException"
  }
}

"Invalid Event Name." Except the event name I was sending was page_liked, which is one of Facebook's own standard event names. It's not some random string I made up.

Normally I'd lose an hour on a thing like this. Open Stack Overflow, open the Facebook Developer Community, open GitHub issues, google "FB Marketing API error 2654," try random combinations until something stuck.

But I didn't bother. I handed it back to Tim and went to do something else.

30 Minutes Later — Tim Had Found Two Separate Bugs

Tim didn't just google the error code. It pulled up the Facebook Marketing API docs across two different versions — the current one (v23.0) and an older one — and diffed them line by line. Two fields had silently changed behavior:

  1. The subtype: ENGAGEMENT field was deprecated in v3.0 — back in September 2018.
    Half the example code on Stack Overflow, tutorial blog posts, and GitHub repos still includes this field. But if you send it now, FB rejects the whole request with "Invalid Event Name" — which has nothing to do with what's actually wrong. The error message points you in completely the wrong direction.
  2. The operator must be "eq", not "=".
    SQL trains your brain to write field = value. But the FB Marketing API filter expects {"operator": "eq", "value": "page_liked"}. If you send "=", the response is — you guessed it — "Invalid Event Name." Same error, totally different root cause. The actual error should say "Invalid Operator." It doesn't.

Same error message, two completely unrelated bugs. That's the part that makes this hard. Without doing a doc-version-to-doc-version diff, there's almost no way to figure out which one's biting you.

And there was a third quirk Tim caught as a bonus:

  • The page_liked event requires retention_seconds: 0. Facebook treats "people who like your page" as a lifetime audience with no time window. If you pass anything else — say 5184000 (60 days), which is a totally reasonable thing to try — you get a different error: subcode 1713214, "Can't Choose Data Time Limit."

Tim patched all three, committed, pushed, and re-ran the script. Response this time: {"id": "120..."}. Audience created. The whole debug-to-green run was about 30 minutes from the moment I handed over the broken script.

The Result

I now have a reusable script at /root/100x-ads/create_audiences.py. Run it once and it creates whichever audiences I want for that campaign.

It built three audiences inside a minute:

  • Page Followers — everyone who likes the page (lifetime) — for retargeting the upcoming campaign.
  • Engaged 30d — anyone who engaged in the last 30 days — for retargeting new content.
  • Engaged 60d — anyone who engaged in the last 60 days — for lowering CAC on awareness campaigns.

For every future campaign, I don't open Ads Manager. I tell Tim what audience I need, Tim runs the script.

The Real Lesson: Big-Platform Error Messages Lie

This is the second or third time I've seen the same pattern. Big platform APIs — Facebook Graph, Google APIs, Stripe — ship error messages that are technically present but practically useless. "Invalid Event Name" when the actual problem is a deprecated field. "Invalid Event Name" when the actual problem is an SQL-style operator. These messages weren't designed to help you debug — they were designed to be returned in a generic 400 wrapper and never updated.

The only reliable way to debug this stuff is to read the API docs across versions and look for what changed. And that's exactly the kind of work an AI agent does better than a human. Tim can read the entire current API doc and the entire previous version's API doc in the time it takes me to find the right tab. I'd be hunting Stack Overflow threads from 2019 hoping for a clue. The AI just reads source-of-truth.

The old version of me — pre-AI-agent — would have either spent a full day swapping random fields one at a time, or given up and gone back to clicking through Ads Manager like a normal person.

This is the same reason I keep arguing that building your own tools beats paying for SaaS. Most ad SaaS products are just wrappers around the FB Marketing API. When FB silently changes a schema, you're stuck waiting for the SaaS to update. With my own AI agent, I diagnose, patch, and ship in 30 minutes.

It also rhymes with two earlier ones I've written about: the time my AI traced a missing Stripe webhook gap in under an hour, and the time it found a hidden Facebook Graph API quirk that was silently downgrading my live clips to 360p. Same shape every time: big platforms have weird quirks, and an AI that can read docs end-to-end and iterate on real API responses chews through them way faster than I can.

Why This Needs an AI Agent on a Private Server

You can't do this with ChatGPT or Claude in a browser tab. Here's why:

  • The script needs the access_token for my FB Ad Account. That's a secret. I'm not pasting it into a public chat window.
  • It has to actually POST to the API, read the real response, and iterate — not just give me an "I think it might be the operator" suggestion that I then have to verify myself.
  • The final script (create_audiences.py) has to live in my own repo so I can run it again next month.
  • It has to git commit and git push so I can see what changed over time.

None of that is possible on a shared chatbot platform. It's only possible on an AI agent running on a private server — with access to my secrets, my repos, my git history, and a real shell.

The shortest version of this story: having an AI agent on a private server that can actually drive the FB Marketing API — debug quirks, write reusable scripts, push to git — is the reason I run ad campaigns without ever opening Ads Manager. If you want the same setup — your own server, your own AI agent, ready to debug API errors and write automation scripts of its own — that's exactly what Newton is. Spin one up in about 10 minutes, no server expertise required.

— Pond