Overview
From a goal to a priced plan in one call: goal (launch, funding, feature or program), product, moment (what goes live and when), window_start, window_end and budget_usd; optionally audience and company (left out, they come from your company context), geography (worldwide), desired_outcome (the goal's usual outcome), constraints and budget_min_usd. The answer's defaults lists every field it filled. The budget is held to this key's mandate: the plan is built within the smaller of budget_usd, the mandate's maximum plan total and what is left of its monthly cap, and a budget_min_usd above either limit is refused (mandate_refused, over_max_plan_total or over_monthly_cap, with the numbers); with no budget_min_usd the campaign is held to the mandate instead. The campaign is started for the brand exactly as from the workspace and the planner builds the plan from creators on sale now. Returns campaign_id and the plan as plan_quote returns it, or plan_note when nothing on sale fits yet. Needs an idempotency_key; a retry with the same key never starts a second campaign. A brand starts at most 3 campaigns in any 24 hours (rate_limited, details.reason daily_campaign_limit, details.resets_at when it reopens).
- Server
https://app.distribution.tech/api/mcp- Scope
campaigns:write- Changes data
- Yes, pass an idempotency_key
- REST endpoint
- POST /campaigns
Arguments
| Name | Type | Required | Description |
|---|---|---|---|
idempotency_key | string | Yes | Your unique id for this request. Retry with the same id and the same arguments to get the same answer; it never runs twice. |
goal | one of "launch", "funding", "feature", "program" | Yes | The campaign's goal: launch, funding or feature (an announcement) or program (steady reach every month). |
product | string | Yes | What is being promoted. |
moment | string | Yes | What goes live and when, e.g. Agent SDK 1.0, public on 4 November. |
window_start | string (date) | Yes | First day posts may go out (YYYY-MM-DD), today or later. |
window_end | string (date) | Yes | Last day posts may go out (YYYY-MM-DD), on or after window_start. |
budget_usd | integer | Yes | The most to spend, in US dollars. The plan is held to this key's mandate: never above its maximum plan total or what is left of its monthly cap. |
audience | string | No | Who needs to care, in a sentence. Leave out to use the audience in your company context. |
geography | string | No | The markets. Leave out for worldwide. |
budget_min_usd | integer | No | The least to spend. Above the mandate's maximum plan total, or what is left of its monthly cap, the campaign is refused. Leave out and the budget is held to the mandate instead of refused. |
desired_outcome | string | No | What a good result looks like. Leave out for the goal's usual outcome (launch: views and clicks on the launch posts). |
company | string | No | Your company's name as the creators should say it. Leave out to use the name in your company context. |
constraints | string | No | Anything the creators must or must not do. |
Call with curl
The server speaks streamable HTTP, so one JSON-RPC tools/call request runs the tool. Set DISTRIBUTION_API_KEY to a key from Developers with the campaigns:write scope; the arguments shown are the required ones.
curl -X POST "https://app.distribution.tech/api/mcp" \
-H "Authorization: Bearer $DISTRIBUTION_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_campaign",
"arguments": {
"idempotency_key": "<string>",
"goal": "launch",
"product": "<string>",
"moment": "<string>",
"window_start": "<date>",
"window_end": "<date>",
"budget_usd": 10
}
}
}'Result
The answer's structuredContent follows the tool's output schema (the same JSON is in its text content). It has these fields:
| Name | Type | Required | Description |
|---|---|---|---|
campaign_id | string (uuid) | Yes | |
status | one of "plan_ready", "no_plan" | Yes | |
plan | null or object | Yes | |
plan_note | string or null | Yes | |
defaults | array of one of "company", "audience", "geography", "desired_outcome" | No | The fields filled because the request left them out. |
budget | object | No | The budget the campaign was stored with. held is true when budget_usd alone was held lower, to what the mandate allows. |
{
"campaign_id": "<uuid>",
"status": "plan_ready",
"plan": {
"plan_id": "<uuid>",
"campaign_id": "<uuid>",
"version": 0,
"status": "awaiting_approval",
"currency": "<string>",
"launch_window_start": "<date>",
"launch_window_end": "<date>",
"terms_fingerprint": "<string>",
"total_cents": 0,
"totals": {},
"lines": [
{
"id": "<uuid>",
"creator": {
"id": "<uuid>",
"name": "<string>",
"handle": "<string>",
"profile_url": "<string>",
"avatar_url": "<uri>",
"followers": 0
},
"creator_id": "<uuid>",
"unit_id": "<uuid>",
"stage_id": "planned",
"stage": "<string>",
"channel": "<string>",
"channel_label": "<string>",
"format": "<string>",
"deliverable": "<string>",
"scheduled_date": "<date>",
"price_cents": 0,
"vetting": "<string>",
"reason": "<string>",
"expected_views_low": 0,
"expected_views_high": 0,
"on_sale": false
}
],
"payment_options": [
{
"rail": "checkout",
"label": "<string>",
"clears": "<string>"
}
],
"agent_payment": "checkout",
"brand_terms": {
"current_version": "<string>",
"current_number": 0,
"url": "<string>",
"accepted_for_this_key": "<string>",
"accepted_number_for_this_key": 0
},
"mandate": {
"key_id": "<uuid>",
"version": 0,
"max_plan_cents": 0,
"monthly_cap_cents": 0,
"channels": [
"<string>"
],
"may_approve": false,
"may_exceed_budget": false,
"expires_at": "<date-time>",
"updated_at": "<date-time>",
"spent_this_month_cents": 0,
"terms_version": "<string>",
"terms_accepted_at": "<date-time>",
"terms_accepted_email": "<string>"
},
"policy": {
"allowed": false,
"refusal": {}
},
"blocked_lines": [
"<uuid>"
],
"over_budget": {
"budget_cents": 0,
"total_cents": 0,
"over_by_cents": 0
},
"order": {},
"valid_while": "terms_fingerprint_unchanged"
},
"plan_note": "<string>",
"defaults": [
"company"
],
"budget": {
"min_usd": 0,
"max_usd": 0,
"held": false
}
}Other tools
inventory: Network coverageresolve_audience: Resolve an audiencecampaign_status: Campaign statusevidence: Proof of deliveryresults: Resultsbrain_get: Company contextcreators_search: Find creatorscreator_get: One creatorcreator_ask_price: Ask for a priceplan_quote: Quote a planplan_add_creator: Add a creatorplan_remove_creator: Remove a creatorplan_move_dates: Move a plan's datesplan_swap_creator: Swap a creatorset_creator_guidelines: Set the creator guidelinesapprove_plan: Approve and get the pay linkarchive_campaign: Archive a campaignrename_campaign: Rename a campaigndelete_campaign: Delete a draft campaignfeedback_send: Send feedbackfeedback_list: Your feedback
Get access
Keys are created in Developers once your brand is approved. Connect an agent to ask for access, then read the agent guide for the full flow.