A homemade wrapper per platform
Google Ads and Meta speak different languages: their own fields, statuses and limits. The shim written for one report outlives the report it was written for.
The REST API v1 and the MCP server run off the same vk_live_… key and the same set of scopes: 31 tools for an assistant and endpoints for campaigns, analytics, Meta leads and rules. A key can be issued read-only, and any write without its scope answers 403.
Google Ads and Meta speak different languages: their own fields, statuses and limits. The shim written for one report outlives the report it was written for.
Claude or ChatGPT can reason about campaigns perfectly well, but it has neither access nor boundaries — the usual choice is a key to everything or nothing.
A token sits in an environment variable with no expiry, no scope and no trail: nobody knows who uses it, or what happens the day it leaks.
In the developer keys section, give it a name, tick the scopes it needs and optionally an expiry in days. The key is shown once; only a SHA-256 hash is stored.
REST calls go to /api/v1 with an Authorization: Bearer, x-api-key or apikey header. An assistant connects to the MCP endpoint /mcp with that same key.
Only granted scopes resolve: without campaigns:write a write returns 403 insufficient_scope, and a campaign created this way lands as a draft, not live.
Campaigns, analytics, Meta leads, rules, health scores and copy generation, exposed to an assistant as ordinary tools behind one key.
Campaigns with pause, resume, performance and a health score, plus analytics, Meta leads, an account overview and automation rules.
campaigns, analytics, rules, health, leads and ai:generate — a dashboard key can be strictly read-only without ever opening writes.
A prefix in the list, a request counter, a last-used timestamp and an expiry; revoking one shuts it off across every integration at once.
The schema is served at /api/docs/openapi.json with interactive docs beside it, so a client is generated rather than hand-written.
Campaigns created through the API or MCP arrive as drafts, writes require a write scope, and nothing reaches the ad platform on its own.
In the developer keys section, press Create key, give it a name, tick the scopes it needs and optionally set an expiry in days. A key of the form vk_live_… is shown exactly once; only its SHA-256 hash is stored. You can revoke a key at any moment and the revocation takes effect immediately.
The MCP server lives at the /mcp endpoint and speaks the Streamable HTTP transport. In your MCP client, point it at that address and add an Authorization: Bearer header with your vk_live_… key. The assistant then sees 31 tools — but only within the scopes granted to that key.
No. Creating a campaign through the API or MCP returns a draft rather than a live campaign, and the response says outright that a human step comes next. Every write needs the campaigns:write scope; without it the call returns 403 insufficient_scope. A key can also be issued read-only.
Campaigns: list, read, create, update, pause, resume, delete, performance and a health score. Analytics: dashboard, spend, conversions and generated reports. Meta leads: lead forms, leads, sync and ingest. Plus an account overview, the list of connected platforms, and automation rules with templates and history.
The default is 100 requests per minute per key, and the value is set when the install is configured, so on your own server it can be raised. Going over returns a rate-limit response — the key itself is not blocked and keeps working in the next window.
A campaign in the API belongs to a platform, and it can only be created where that ad account is already connected — otherwise the response says the platform needs connecting first. A separate call returns the list of connected platforms along with token state, so you can check before the first write.
A key is created with the scopes and expiry you choose and revoked in one click. Start read-only and widen the scopes once you have watched it behave.