Skip to content
reebuff

MCP

MCP server

The console as tools. Connect with an API key; read tools need read, write tools need manage.

Connect

POST/api/ads/mcpkey (read, manage)
Claude Code
claude mcp add --transport http freebuff-ads https://freebuff.com/api/ads/mcp \
  --header "Authorization: Bearer $FREEBUFF_ADS_API_KEY"
Cursor, Windsurf, VS Code
{
  "mcpServers": {
    "freebuff-ads": {
      "url": "https://freebuff.com/api/ads/mcp",
      "headers": { "Authorization": "Bearer fbadv_…" }
    }
  }
}

Streamable HTTP, stateless, plain JSON. Live keys only. Ask the agent to call get_account first.

Rules

  • Cents. Pacific days. Report ranges default to 30 days, max 366.
  • Lifecycle: create_campaign → submit_campaign → review → pause_campaign / resume_campaign.
  • Images by public https URL, never inline.
  • delete_campaign needs confirm: true.
  • No tool tops up, changes a card, or mints a key.
  • 120 requests a minute; one JSON-RPC message per request, ≤ 64 KiB.

Tools (28)

Account

get_accountreadThe account this key belongs to: company, review status, balance, card on file, and the key’s scopes. Call it first.

No inputs.

Returns account, balanceCents, hasCard, apiKey.scopes, consoleUrl

get_billingreadBalance, card on file and the statement for one month, the same figures the invoice is built from.
InputTypeDescription
monthoptionalYYYY-MMStatement month (Pacific). Default: this month.

Returns balanceCents, creditLineCents, card details, autoReloadEnabled, statement, consoleUrl

Top-ups and card changes happen in the console at the returned URL. There is no tool for them.

list_api_keysreadThe keys on the account: display prefix, mode and creation date only. Keys are minted and revoked in the console.

No inputs.

Returns keys[] { prefix, mode, createdAt }, consoleUrl

list_placementsreadThe placements a campaign can run on: id, surface, and what the unit looks like. Use the ids in create_campaign.

No inputs.

Returns placements[]

Campaigns

list_campaignsreadEvery campaign with its status, caps, spend and delivery totals over a range, plus account totals: the console overview.
InputTypeDescription
fromoptionalYYYY-MM-DDFirst day. Default: 29 days before to.
tooptionalYYYY-MM-DDLast day. Default: today.

Returns account, totals, campaigns[] { id, name, status, billingModel, cpcCents, dailyCapCents, spentTodayCents, conversions, totals, reach }, deliveryBreakdowns[], reporting, consoleUrl

get_campaignreadOne campaign in full: terms, flight, placements, pricing, every creative with its review status and delivery, and why it is not serving if it is not.
InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.
fromoptionalYYYY-MM-DDFirst day. Default: 29 days before to.
tooptionalYYYY-MM-DDLast day. Default: today.
includeTrackingoptionalbooleanAlso return whether its conversion tracking works (Working, Not set up, Too early to tell, Stopped reporting) with the next step. Costs an extra read. Default false.

Returns campaign { …, creatives[], pricing, tracking? }, consoleUrl

create_campaignmanageCreate a draft: name, https landing URL, daily budget, flight dates, placement ids and one or more creatives. Drafts cost nothing and do not serve until submitted and reviewed.

Needs a pending or approved account.

InputTypeDescription
namerequiredstringUp to 120 characters.
landingUrlrequiredstringAn https URL, up to 2000 characters.
dailyCapCentsrequiredintegerDaily budget in cents, 5000 to 500000.
flightStartrequiredYYYY-MM-DDFirst day of delivery (Pacific).
flightEndrequiredYYYY-MM-DD | nullLast day, on or after the start, or null for open-ended. The key must be present.
placementIdsrequiredstring[]One or more ids from list_placements, each once.
creativesrequiredCreative[]At least one, up to 25. Each: title (120 chars, at most one *accent*), body (500), cta (80), and optional landingUrl, expandedBody (240), diagram (40), bullets (3 × 40), brandColor and brandInk (#rrggbb).
conversionEventTypeoptionalstringsignup_completed, demo_booked, trial_started, installation_completed or subscription_started.
targetCpaCentsoptionalinteger | null100 to 10,000,000.
countryTargetingoptional{ mode, countries } | nullmode include or exclude; up to 60 uppercase ISO-3166-1 alpha-2 codes.
frequencyCapPerHouroptionalinteger | null1 to 3; can only lower the platform cap.
sponsoredProcedureoptionalstring | nullFor an agentic campaign: the onboarding procedure (up to 8000 characters) with a tracked bfcid link.
sponsoredTargetingoptionalstring | nullWho the agentic proposal is for (up to 2000 characters). Needs sponsoredProcedure.

Returns id, status: "draft", consoleUrl, next

Unknown fields are rejected. Validation is the console’s, with the same messages.

update_campaignmanageReplace a campaign’s configuration with a full new one, the same fields as create_campaign. A draft stays a draft; an approved campaign takes the edit immediately.

Needs a pending or approved account.

InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.
campaignrequiredobjectThe full configuration. Include each existing creative’s id to keep it and its history; a creative without an id is new.

Returns id, consoleUrl

A full replacement, not a patch. Refused with conflict once a campaign is no longer editable.

set_campaign_imagemanageAttach a logo or a sponsor-break hero from a public https URL. Freebuff downloads it once, validates it as the console upload does, and keeps its own copy.

Needs a pending or approved account.

InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.
kindrequired"logo" | "hero"logo: a static square PNG or JPEG, 64 to 512 px per side, re-encoded to PNG. hero: a static 16:10 PNG, JPEG or WebP, at least 1024×640. Each at most 1024 KB.
imageUrlrequiredstringA direct https link on port 443 to a public hostname that answers 200 with an image within 10 seconds; at most three redirects, only to public https hosts. No IP addresses, localhost or internal names.

Returns id, kind, mediaType, consoleUrl

Works on draft, paused and live campaigns, not while one is in review. On a draft the creatives return to pending review; on a live campaign the image applies at once and is reviewed afterwards.

submit_campaignmanageSend a draft for review. Once the account is approved, a later campaign may be approved automatically and go live on submit.

Needs a pending or approved account.

InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.

Returns id, consoleUrl

resume_campaignmanageStart or restart delivery of an approved, paused campaign.

Needs a approved account.

InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.

Returns id, consoleUrl

pause_campaignmanageStop delivery immediately. The campaign keeps its approval and its reporting; resume_campaign restarts it.

Needs a approved account.

InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.
reasonCodeoptionalstringtoo_expensive, too_few_results, wrong_audience, editing, budget, finished or other.
reasonNoteoptionalstringFree text, up to 1000 characters.

Returns id, consoleUrl

delete_campaignmanageDelete a campaign permanently. Ask the person first.

Needs a pending or approved account.

InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.
confirmrequiredbooleanMust be true. Without it the tool answers confirmation_required and does nothing.

Returns id, deleted: true

preview_adsreadHow the account’s creatives render on each surface, as the console’s preview shows them. Optionally one campaign.
InputTypeDescription
campaignIdoptionalstringA campaign id from list_campaigns.

Returns creatives[] { id, campaignId, title, body, cta, landingUrl, imageUrl, heroImageUrl, status, placements }

Image URLs open with a signed-in console session, not with the API key.

list_activationsreadCharged activations for one campaign: when each happened, on which placement and creative, and the click it came from.
InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.

Returns activations[] { occurredAt, occurredDay, placementId, creativeTitle, clickedAt }, consoleUrl

Answers too_large when there are too many to return; export from the console instead.

create_test_clickmanageMint a test click id for a campaign so a conversion postback can be exercised end to end. Test conversions never bill or count.
InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.

Returns clickId, campaignId, eventType, expiresAt, eventId, conversionPayload, requiredTrackingRail

Valid for about 30 minutes. Rate limited; answers rate_limited when exceeded.

Pixel and goal rules

get_pixel_setupreadThe pixel for this account: the install snippets and tag id, where the tag has been seen, the data level and other settings, analytics events seen in the last 7 days, and each campaign with whether goal rules may be added.

No inputs.

Returns tagId, snippet, snippetWithInlineCalls, pinnedSnippet, cspLines, settings, registeredDomains, tagSeen, analyticsEventsSeen, campaigns, consoleUrl

update_pixel_settingsmanageChange what the pixel collects, the linked domains the click follows visitors to, extra site-search keys and extra query parameters to keep.

Needs a pending or approved account.

InputTypeDescription
dataLeveloptionalstringconversions, standard or full.
linkedDomainsoptionalstring[]Up to 10 registrable domains. Replaces the stored list.
searchKeysoptionalstring[]Query keys read as site search. Replaces the stored list.
queryAllowlistoptionalstring[]Query keys kept on page views. Replaces the stored list.

Returns settings

list_conversion_rulesreadThe no-code goal rules on one campaign, and whether new rules are refused on it and why.
InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.

Returns campaign, rules[]

create_conversion_rulemanageCount an analytics event or a page visit as a conversion goal on a campaign. At most 5 active rules per campaign. Pixel conversions are never charged.

Needs a pending or approved account.

InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.
kindrequired"analytics_event" | "url"What to match.
matchrequiredstringThe event name exactly as sent (a letter, then up to 63 letters, digits, spaces or _ . : -), or a path with * for one segment. gtm.* never matches.
goalEventTyperequiredstringsignup_completed, trial_started, demo_booked, installation_completed or subscription_started.

Returns rule

Refused with conflict on a campaign billed per conversion, or whose server postback reported a live goal conversion in the last 30 days.

disable_conversion_rulemanageTurn off one goal rule. Conversions it already recorded stay. To change a rule, turn it off and create another.

Needs a pending or approved account.

InputTypeDescription
campaignIdrequiredstringA campaign id from list_campaigns.
ruleIdrequiredstringFrom list_conversion_rules.

Returns rule

Reporting

get_delivery_reportreadImpressions, clicks, spend and conversions per day over a range, optionally grouped by campaign, creative, placement, surface or country and filtered by any of those.
InputTypeDescription
fromoptionalYYYY-MM-DDFirst day. Default: 29 days before to.
tooptionalYYYY-MM-DDLast day. Default: today.
groupByoptionalstringcampaign, creative, placement, surface or country.
campaignIdsoptionalstring[]Limit to these ids, at most 50.
creativeIdsoptionalstring[]Limit to these ids, at most 50.
placementIdsoptionalstring[]Limit to these ids, at most 50.
surfacesoptionalstring[]Limit to these ids, at most 50.
countriesoptionalstring[]Limit to these ids, at most 50.
maxRowsoptionalinteger1 to 5000. Default 1000.

Returns range, groupBy, reporting, rows[] { day, settled, campaignId, …, totals, conversions, conversionsByEvent, traffic }, conversionEventTypes, reach

The same data as the reporting API’s delivery endpoint. Answers too_large when the selection exceeds maxRows.

list_conversionsreadConversion events reported back to Freebuff over a range, newest first, with a cursor for the next page. Test conversions are excluded unless includeTest is true.
InputTypeDescription
fromoptionalYYYY-MM-DDFirst day. Default: 29 days before to.
tooptionalYYYY-MM-DDLast day. Default: today.
campaignIdsoptionalstring[]Limit to these ids, at most 50.
eventTypesoptionalstring[]Limit to these ids, at most 50.
includeTestoptionalbooleanDefault false.
limitoptionalinteger1 to 500. Default 100.
cursoroptionalstringThe nextCursor of the previous page.

Returns range, conversions[] { eventId, campaignId, campaignName, eventType, occurredAt, settlementStatus, chargedCents, isTest, reportedVia, matchedVia }, nextCursor

Team

list_teamreadMembers of the account and the invitations still open.

No inputs.

Returns members[] { id, email, name, role, createdAt }, invites[] { id, email, role, createdAt, expiresAt }, consoleUrl

invite_membermanageEmail an invitation to join the account as a member, sent in the owner’s name.

Needs a approved account.

InputTypeDescription
emailrequiredstringAn email address, up to 320 characters.

Returns invite { id, email, role, createdAt, expiresAt }, consoleUrl

Sends a real email.

revoke_invitemanageWithdraw an open invitation by its id.

Needs a approved account.

InputTypeDescription
inviteIdrequiredstringFrom list_team.

Returns inviteId, revoked: true

remove_membermanageRemove a member by id. An owner cannot be removed this way.

Needs a approved account.

InputTypeDescription
memberIdrequiredstringFrom list_team.

Returns memberId, removed: true

Errors

A refusal is a tool result with isError and a stable code, never a JSON-RPC error. Do not retry it.

Refusal
{
  "isError": true,
  "content": [{ "type": "text", "text": "insufficient_scope: create_campaign needs an API key with the \"manage\" scope." }],
  "structuredContent": { "error": "insufficient_scope", "message": "…" }
}
CodeMeaning
insufficient_scopeKey lacks the scope.
not_allowedAccount state forbids it, or owner-only.
not_foundNot on this account.
conflictLifecycle refused: no longer editable, rule limit, open invite.
invalid_inputValidation, bad range, bad cursor, bad image.
confirmation_requireddelete_campaign without confirm: true.
not_availableFeature not on for this account.
too_large, fetch_failed, rate_limited, internal_errorAs named.
HTTP-level answers
StatusBodyMeaning
400invalid requestNot one JSON-RPC object, or invalid JSON.
401unauthorizedNo key, revoked, or a test key.
404Not found.MCP not enabled for this account.
405…GET and DELETE: no event stream, no session.
413request too largeOver 64 KiB.
429rate limitedRetry-After is set.