Creative Desk API
Let your own tools and AI assistants read the creative library — copy, media, dimensions, what the video says, and how each creative has performed on every network — and record the ads they build from it.
- Library → rail → API keys → Creative Desk API. Name the key (e.g. “Claude Meta assistant”), tick what it may do, click Create key. Permissions can be changed later with Permissions on the key — same key, same connector URL; reconnect the connector in Claude to see new tools.
- Copy the Claude connector URL it shows (
…/mcp.php?key=cdk_…). The key is shown once only. - In Claude: Settings → Connectors → Add custom connector, paste the URL, name it Creative Desk. Leave the OAuth fields empty.
- Turn the connector on in the chat or project your Meta assistant runs in. It gets nine tools:
get_winners,get_insights,search_creatives,get_creative,list_campaigns,launch_history,create_creative,update_creative,record_launch.
Treat the connector URL like a password: it contains the key. Revoke it in the same panel if it ever leaks, and make a new one.
A starting instruction for the assistant
Each day, before building Meta campaigns:
0. Call get_winners (platform="meta", then all networks) and get_insights to see
which creatives, states, angles and headlines are converting, and
launch_history to see what already went out recently.
1. Call search_creatives with not_launched_on="meta", status="approved", and the
campaign (vertical) you are launching for. Prefer creatives with winning=true or
strong performance.by_platform on other networks (low cpa, high roas).
2. For each creative you use: upload media.url to Meta (it is a direct, signed file
link valid 24h), and use copy.headline / copy.primary_text / copy.description /
copy.landing_url for the ad unless told otherwise. Pick placements from
media.orientation (vertical = Stories/Reels, square/horizontal = Feed).
3. Create everything PAUSED unless I say otherwise.
4. After each ad is created, call record_launch with creative_id, platform="meta",
ad_id, account_id, account_name, campaign_id, campaign_name, adset_id,
adset_name and status, so Creative Desk links the ad to the creative.
Authentication
Every call carries a key: Authorization: Bearer cdk_…. Where a header can’t be set, X-Api-Key: cdk_… or ?key=cdk_… also work. Keys are stored hashed; a lost key can’t be shown again — revoke it and create another.
| Permission | Can |
|---|---|
| Read (every key) | Every GET below: creatives, winners, insights, launch history, media |
| Create & edit creatives | v1_create, v1_update, v1_launched |
| TikTok: launch | Create campaigns, ad groups and ads — live by default (send status: "paused" to hold them) |
| TikTok: pause | Pause ads, ad groups and campaigns — it cannot resume |
| TikTok: budgets | Set an ad group’s budget — nothing else |
| TikTok: rules | Create, edit, switch on/off, test-run and read TikTok automated rules — pause and budget rules only; it cannot make, switch on or run a rule that resumes |
Base URL: https://ads-creatives.addrawtech.com/api.php. Add &pretty=1 for indented JSON. Errors are {"ok":false,"error":"…"} with a 4xx status.
Endpoints
GET?action=v1_me
Checks the key. {"ok":true,"key":{"name":"Claude Meta assistant","scope":"write"}}
GET?action=v1_campaigns
The Library campaigns (verticals) with creatives, winning and live counts.
GET?action=v1_creatives
Search the library. All filters are optional and combine with AND.
| Param | Meaning |
|---|---|
campaign | Library campaign name(s), comma-separated |
status | draft, review, approved, live, adplexity, crawler, archived, rejected (comma-separated) or all. Default: all but archived & rejected |
type | image, video, gif |
winning | 1 = only creatives marked winning |
q | Text in the name, tags, headline, primary text, description or the words spoken in the video |
tag | Exact tag |
orientation | vertical, horizontal, square |
launched_on / not_launched_on | meta, newsbreak, tiktok, snapchat |
launched_within_days | Launched (from any launcher or the API) in the last N days |
min_conversions, min_spend | Lifetime thresholds |
created_since, updated_since | ISO date (2026-09-01) |
has_copy | 1 = only creatives with primary text |
order | newest (default), updated, spend, conversions, roas, cpa |
limit, offset | Page size 1–200 (default 50); follow next_offset |
curl -H "Authorization: Bearer $CDK" \
"https://ads-creatives.addrawtech.com/api.php?action=v1_creatives&campaign=Auto¬_launched_on=meta&status=approved&limit=20"
Each creative:
{
"id": "k3x9…", "name": "Auto hook A", "type": "video", "status": "approved",
"campaign": "Auto", "tags": ["ugc"], "winning": true,
"media": { "url": "https://…/api.php?action=v1_media&f=…&exp=…&sig=…",
"thumbnail": "…", "width": 1080, "height": 1920,
"orientation": "vertical", "duration_s": 21.4, "expires_in_s": 86400 },
"copy": { "headline": "…", "primary_text": "…", "description": "…",
"landing_url": "https://…", "page_url": null },
"spoken_words": "first 600 characters of the transcript…",
"performance": {
"total": { "spend": 50, "conversions": 5, "impressions": 1000, "clicks": 20,
"revenue": 120, "ctr": 2, "cpa": 10, "roas": 2.4 },
"by_platform": { "newsbreak": { …same fields… } } },
"launched": { "platforms": ["newsbreak"], "ad_ids": { "newsbreak": ["111"] },
"count": 3, "last_at": "2026-09-24T09:12:00+00:00", "ad_account": "…" },
"created_at": "…", "updated_at": "…", "library_url": "…"
}
by_platform comes from the same sync the Scoreboard uses, so it is as fresh as the last sync of that network. performance.total is the creative’s lifetime roll-up.
GET?action=v1_creative&id=…
One creative in full: everything above, the whole transcript in spoken_words, and versions — its other files (sizes, edits), each with a signed url.
Also carries ads — every ad made from it with that ad’s own spend, conversions, CPA, ROAS and campaign name — and, for competitor ads, research (days running, ad counts, markets).
GET?action=v1_winners
Every launched creative ranked against its own Library campaign. Each gets window (its numbers in the last sync of each network), vs_campaign (the campaign’s blended CPA/ROAS and this creative’s ratio to it) and a verdict: winner (≥ min_conversions and CPA ≤ 0.8× the campaign’s), average (≤ 1.15×), loser (worse, or no conversions after spending 1.5× the campaign CPA), promising, not_enough_data. The response also has campaign_benchmarks and data_as_of per network.
| Param | Meaning |
|---|---|
platform | Judge on one network only (default: all combined) |
campaign | Library campaign(s) |
verdict | e.g. winner or winner,promising |
rank_by | cpa (default, relative to campaign), roas, conversions, ctr, spend |
min_spend, min_conversions | Thresholds before judging (default 20 and 2) |
limit | Default 25, max 200 |
GET?action=v1_insights
The States page roll-up: spend, conversions, CPA, ROAS and CTR by states, angles (the message with the state taken out), exact headlines, exact descriptions, and state_x_angle. Params: platform, min_spend, limit.
GET?action=v1_launches
The Launch log: every launch from the launchers, 1-click and the API, with account, campaign, ad set, ad id, status and error. Params: days (30), creative_id, platform, errors_only=1, limit.
POST?action=v1_create read + write keys
Add a creative. Send the file one of three ways: media_url (a public link — the server downloads it), media_base64 with filename, or a multipart form with a file field. JPG, PNG, WebP, GIF, MP4, MOV, WebM up to 128 MB. Size, length and orientation are read from the file itself.
curl -X POST -H "Authorization: Bearer $CDK" \
"https://ads-creatives.addrawtech.com/api.php?action=v1_create" -d '{
"media_url": "https://…/variation-3.mp4",
"name": "Drivers over 50 — v3", "campaign": "Auto", "status": "draft",
"tags": ["variation", "over-50"],
"headline": "…", "primary_text": "…", "description": "…",
"landing_url": "https://…", "thumbnail_url": "https://…/poster.jpg"
}'
# or upload a local file
curl -X POST -H "Authorization: Bearer $CDK" -F file=@hook.mp4 -F campaign=Auto \
"https://ads-creatives.addrawtech.com/api.php?action=v1_create"
New creatives are draft unless status is review or approved, are tagged via-api, and must go in an existing Library campaign (default: the first). The response is the full creative, as v1_creative returns it.
POST?action=v1_update read + write keys
Edit a creative: {"id": "…", …} with any of name, campaign, status, winning, tags (replace), add_tags, remove_tags, headline, primary_text, description, landing_url, page_url. Only fields sent change; "" clears a copy field. Every change is written to the activity feed as api:<key name>.
GETmedia.url
The file itself. The link is signed and expires in 24 hours, needs no key, and supports Range requests — hand it straight to Meta’s file_url / image_url upload. An expired link returns 410: fetch the creative again for a fresh one.
POST?action=v1_launched read + write keys
Record an ad you created. Creative Desk adds the ad id to the creative (its stats then sync onto it), adds the network to its platforms, writes the Launch log and the activity feed. Posting the same ad id again is a no-op.
curl -X POST -H "Authorization: Bearer $CDK" -H "Content-Type: application/json" \
"https://ads-creatives.addrawtech.com/api.php?action=v1_launched" -d '{
"creative_id": "k3x9…", "platform": "meta", "ad_id": "120215…",
"account_id": "act_123", "account_name": "Auto CB1",
"campaign_id": "120215…", "campaign_name": "auto_0925_1",
"adset_id": "120215…", "adset_name": "TX", "ad_name": "Auto hook A",
"status": "PAUSED", "landing_url": "https://…", "mark_live": false
}'
Required: creative_id, platform, ad_id. mark_live: true also sets the creative’s Library status to live.
TikTok
With a TikTok permission the key drives the TikTok launcher’s own actions — the same code the Launcher page and the ⚡ button run — with Authorization: Bearer cdk_…. Through MCP it is simpler: the tools below do the steps for you.
| MCP tool | Permission | Does |
|---|---|---|
tiktok_accounts | any TikTok | Connected advertisers |
tiktok_account_assets | any TikTok | One advertiser’s campaigns, ad groups (with budgets), identities, pixels |
tiktok_templates | launch | Saved TikTok 1-click templates |
tiktok_launch | launch | 1–5 creatives into a template, an existing ad group, or a new campaign + ad group. Uploads each file, creates the ads active (or paused with status: "paused"), records them on the creatives and in the Launch log. Returns campaign_id, adgroup_id, ad ids |
tiktok_pause | pause | {advertiser_id, level: ad|adgroup|campaign, id} |
tiktok_budget | budgets | {advertiser_id, adgroup_id, budget} |
tiktok_rules | rules | Every TikTok rule, what it does, its last run and result, and when the scheduler last ran |
tiktok_rule_save | rules | Create or edit a rule: {name, advertiser_id, level, conditions:[{metric, op, value}], window, action: pause|budget_up|budget_down, action_value, interval_minutes, campaign_ids, name_contains} |
tiktok_rule_toggle / tiktok_rule_delete | rules | Switch a rule on or off / remove it |
tiktok_rule_test | rules | Run one rule now — for real |
tiktok_rules_log | rules | What the rules did, with the numbers at the time |
tiktok_launch {
"creative_ids": ["k3x9…"],
"advertiser_id": "7xxxxxxxxxxxx",
"campaign": {"name": "auto_0926_api", "objective": "WEB_CONVERSIONS"},
"adgroup": {"name": "TX", "locationIds": ["4736286"], "budget": 30,
"optimizationGoal": "CONVERT", "pixelId": "…", "optimizationEvent": "…"},
"ad": {"text": "…", "url": "https://…", "cta": "LEARN_MORE"}
}
# or: {"creative_ids": [...], "template_id": "…"} or {"creative_ids": [...], "advertiser_id": "…", "adgroup_id": "…"}
Every action a key takes is logged as api:<key name> in the activity feed and the Launch log.
MCP (Claude connector)
POST /mcp.php speaks the Model Context Protocol over Streamable HTTP (JSON responses, no sessions). The same key goes in ?key= or the Authorization header. Tools map one-to-one to the endpoints above and take the same parameters as JSON arguments.
| Tool | Same as |
|---|---|
list_campaigns | v1_campaigns |
search_creatives | v1_creatives |
get_creative | v1_creative |
get_winners | v1_winners |
get_insights | v1_insights |
launch_history | v1_launches |
create_creative | v1_create (media_url or media_base64) |
update_creative | v1_update |
record_launch | v1_launched |
Using the Claude API or Agent SDK instead of the app? Pass the URL as a remote MCP server, or call the REST endpoints as ordinary tools.