Developer docs
Everything you need to build on OwnMyAds without putting an ad account at risk. OwnMyAds is a client for the official Meta Marketing API, so anything you build talks to Meta the same way the app does.
How it works
Ad data never passes through OwnMyAds servers. The app, the CLI and the MCP server call graph.facebook.com directly from your device with your business key. Our server only handles your login, billing, the optional encrypted key sync and the AI agent, which receives the rows you send it and returns a plan.
Business key
A business key is a Meta system user access token. It belongs to your Business portfolio instead of a personal profile, so a restricted or banned profile can’t lock you out.
- Business Settings → Users → System users → Add. Pick Employee, not Admin, unless you need to manage the business itself.
- Assign assets: only the ad accounts (and Pages, pixels) the key should touch. Give Manage for ad accounts you want to edit, View for read only.
- Click Generate token, set expiration to Never and tick every permission in the list (ads_management, ads_read, business_management, catalog_management, pages_manage_ads, pages_read_engagement, pages_show_list and the rest). That gives OwnMyAds everything Ads Manager can do.
Building your own read only integration? Make a separate key with only ads_read and View access.
Open System users ↗Ad account access ↗
CLI
npm i -g https://ownmyads.app/cli.tgzZero dependencies, Node 18+. ownmyads login saves your key to ~/.ownmyads/config.json on your computer only. In CI, skip the file and set an environment variable.
OWNMYADS_TOKEN | Business key. Takes priority over the saved one. META_TOKEN also works. |
ownmyads campaigns --range last_7d | Also adsets, ads. Ranges: today, yesterday, last_7d, last_14d, last_30d, this_month, last_month, maximum |
ownmyads off|on <id> | on asks before it spends |
ownmyads budget <id> 120 | Daily or lifetime, whichever the object uses |
ownmyads dup <id> | The copy starts off |
ownmyads ask "…" | AI agent plan, you confirm each run. Needs ownmyads signin and an active plan |
MCP server
claude mcp add ownmyads -- ownmyads mcpStdio JSON-RPC, works in Claude Code, Cursor and any MCP client. Config for clients that use JSON:
{ "mcpServers": { "ownmyads": { "command": "ownmyads", "args": ["mcp"], "env": { "OWNMYADS_TOKEN": "…" } } } }
| Tool | Does | Risk |
|---|---|---|
list_ad_accounts | Ad accounts the key can reach | Read |
list_campaigns | Campaigns, ad sets or ads with spend, purchases, ROAS, CPA. Args: level, account, range | Read |
set_status | ACTIVE or PAUSED. Turning on spends money | Spends |
set_budget | Budget in account currency, major units | Spends |
duplicate | Copy starts paused | Write |
rename | Rename an object | Write |
Keep your MCP client’s approval prompt on for the tools marked Spends. The server tells the model to ask before turning anything on or raising budgets, but your client is the real gate.
Agent API
The same planner the app uses. It never touches Meta: you send rows, it returns a reply and a list of actions, and you apply them yourself.
POST https://ownmyads.app/api/ai
Cookie: session from /api/login (or use ownmyads ask)
{ "instruction": "Pause every ad under 1.5 ROAS",
"level": "ad", "currency": "USD",
"rows": [{ "id": "1202…", "level": "ad", "name": "Static v2", "status": "ACTIVE",
"spend": 61.2, "purchases": 0, "roas": 0, "cpa": null }] }
→ { "reply": "1 ad matches…",
"actions": [{ "type": "pause", "id": "1202…", "reason": "ROAS 0.00" }] }
Action types: pause, activate, set_budget, scale_budget (percent), rename, duplicate. Matching runs as code on our side, so counts and thresholds are exact. Requests must come from ownmyads.app or a non-browser client; browsers on other origins are refused.
Graph API directly
Anything the app does is a plain Marketing API call. Pause an ad:
curl -X POST "https://graph.facebook.com/v23.0/<AD_ID>" \ -d status=PAUSED -d access_token="$OWNMYADS_TOKEN"
Budgets are in cents (daily_budget=12000 is $120). Insights: GET /act_<ID>/insights?level=ad&date_preset=last_7d&fields=spend,actions,purchase_roas.
Safety rules
- Least privilege. One system user per integration, Employee role, only the ad accounts it needs.
- Never ship a key to a browser you don’t control. No keys in front end code, URLs, repos or logs. Use env vars and a secrets manager.
- Read first, write on confirm. Anything that turns on delivery or raises spend should need a human yes.
- Create paused. New campaigns, ad sets, ads and copies start PAUSED, then a person turns them on.
- Cap changes. Limit budget edits per run (for example ±30%) and log every change with the old value so it can be undone.
- Revoke fast. Business Settings → System users → Revoke tokens kills a key everywhere instantly. In the app, remove the business under Businesses.
- Key sync is optional. If you tick “Save to my account”, the key is encrypted with AES-GCM before it’s stored and only your signed in session can read it back.
Limits
| Meta Marketing API | Meta’s own per account rate limits apply. On error code 17 or 80004, back off and retry later. |
| Agent | 200 requests a day per account on a paid plan. Demo: 15 a day. |
| Login links | 4 an hour per email |
OwnMyAds is not affiliated with Meta. Questions: email [email protected].