API · V1

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.

Connect your Claude assistant in two minutes
  1. 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.
  2. Copy the Claude connector URL it shows (…/mcp.php?key=cdk_…). The key is shown once only.
  3. In Claude: Settings → Connectors → Add custom connector, paste the URL, name it Creative Desk. Leave the OAuth fields empty.
  4. 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.

PermissionCan
Read (every key)Every GET below: creatives, winners, insights, launch history, media
Create & edit creativesv1_create, v1_update, v1_launched
TikTok: launchCreate campaigns, ad groups and ads — live by default (send status: "paused" to hold them)
TikTok: pausePause ads, ad groups and campaigns — it cannot resume
TikTok: budgetsSet an ad group’s budget — nothing else
TikTok: rulesCreate, 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.

ParamMeaning
campaignLibrary campaign name(s), comma-separated
statusdraft, review, approved, live, adplexity, crawler, archived, rejected (comma-separated) or all. Default: all but archived & rejected
typeimage, video, gif
winning1 = only creatives marked winning
qText in the name, tags, headline, primary text, description or the words spoken in the video
tagExact tag
orientationvertical, horizontal, square
launched_on / not_launched_onmeta, newsbreak, tiktok, snapchat
launched_within_daysLaunched (from any launcher or the API) in the last N days
min_conversions, min_spendLifetime thresholds
created_since, updated_sinceISO date (2026-09-01)
has_copy1 = only creatives with primary text
ordernewest (default), updated, spend, conversions, roas, cpa
limit, offsetPage 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&not_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.

ParamMeaning
platformJudge on one network only (default: all combined)
campaignLibrary campaign(s)
verdicte.g. winner or winner,promising
rank_bycpa (default, relative to campaign), roas, conversions, ctr, spend
min_spend, min_conversionsThresholds before judging (default 20 and 2)
limitDefault 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 toolPermissionDoes
tiktok_accountsany TikTokConnected advertisers
tiktok_account_assetsany TikTokOne advertiser’s campaigns, ad groups (with budgets), identities, pixels
tiktok_templateslaunchSaved TikTok 1-click templates
tiktok_launchlaunch1–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_pausepause{advertiser_id, level: ad|adgroup|campaign, id}
tiktok_budgetbudgets{advertiser_id, adgroup_id, budget}
tiktok_rulesrulesEvery TikTok rule, what it does, its last run and result, and when the scheduler last ran
tiktok_rule_saverulesCreate 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_deleterulesSwitch a rule on or off / remove it
tiktok_rule_testrulesRun one rule now — for real
tiktok_rules_logrulesWhat 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.

ToolSame as
list_campaignsv1_campaigns
search_creativesv1_creatives
get_creativev1_creative
get_winnersv1_winners
get_insightsv1_insights
launch_historyv1_launches
create_creativev1_create (media_url or media_base64)
update_creativev1_update
record_launchv1_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.