Test fixture — for the fatmira site graph. Not a real service; nothing here describes anything that exists. Build 3.
the-best-meta-ads-bench-simulator.cc

A Meta Marketing API you can point a test at

This host answers Graph requests the way graph.facebook.com answers them, over a publicly-valid certificate, with no Meta login, no app review and no request leaving this machine. It exists so the browser Meta route — MCP → console → engine → extension → Graph — can be run end to end before it is ever pointed at a real advertiser's account.

Point at it

graph.the-best-meta-ads-bench-simulator.cc

One constant. In the extension that is GRAPH_HOST in client/src/broker/graph.ts, and it must stay a build-time value: a host that a server could name is an SSRF primitive aimed out of a browser that is logged in to Meta, which is worse than the problem the browser route was chosen to avoid. Everything else — the version, the node shape, the edge names, the field spellings, the error bodies — is already what the client sends.

API version
v26.0
Ad account
act_10000000000001
Access token
EAAsim.default
Second account
act_10000000000002

It is unhelpful on purpose

A simulator that answered the way a client hopes would endorse that client's model of Meta rather than test it. So this one reproduces the parts of Graph that people get wrong:

What it doesWhy that matters
HTTP 400 for every error class a dead token, a throttle, a missing object and a bad version are all 400. The verdict is error.code in the body, never the status.
paging.next carries access_token= Graph builds that URL from the request it received, so a token comes back inside the response body and into whatever reads it next.
promote_pages rows carry a Page access_token a write-capable credential nobody asked for, in the default representation of a node you did ask for.
an unknown field is dropped in silence misspell one and you get a row with a missing column, not an error. This is the whole reason a curated field list exists.
money is a string of minor units "5000" is 50.00. Treat it as major units and you are wrong by 100×, in the direction that looks plausible.
ids are strings of ~15 digits parse them as numbers and they corrupt silently past 253.
status and effective_status disagree an ACTIVE ad set inside a paused campaign reports CAMPAIGN_PAUSED and spends nothing.

Make it fail

Every error class the client claims to handle is reachable by swapping the token. Nothing breaks; the workspace is untouched.

Tokencodesubcodemeaning
EAAsim.expired190460session expired — permanent, only the operator can fix it
EAAsim.throttled17user request limit — retryable
EAAsim.buc80004business use case limit — retryable
EAAsim.forbidden200missing ads_management permission — permanent
EAAsim.oops2 Graph's own fault — the one response that is 500, not 400

State

One shared workspace that always works, so a bench run needs no setup. Any token spelled EAAsim.<name> forks its own private copy on first use, so two agents writing at once do not collide. POST /api/adsim/reset puts either one back to the seed, and so does restarting the container.