API resource

Ads (add-on)

Run paid ads on Meta (Facebook and Instagram), Google, TikTok, X and ChatGPT (OpenAI) with the same key. Needs the Ads add-on ($19.99/month on any plan, from the Ads page in Creator OS); without it every call returns 402 ads_addon_required. Connect an ad network, pick one of its ad accounts, then create, boost, pause and measure. Ads are ad_ ids and audiences aud_; campaign, ad set and ad account ids are the networks' own (e.g. act_123on Meta), exactly as shown in their dashboards. Budgets are whole units of the ad account's currency (25 = $25). Creates spend real money unless you pass status: "PAUSED".

Connect an ad network

GET/v1/connect/{network}/ads

meta runs through the workspace's Facebook Page (no sign-in at all when it already has ads access), google is its own Google sign-in, linkedin reuses the connected LinkedIn account's sign-in (connect LinkedIn first; usually no second login), tiktok is its own TikTok for Business sign-in (linked to the connected TikTok account when there is one, which enables Spark Ads), x hangs off the connected X account (account_id when there are several). Send the user to auth_url. When the network reuses a connected account's token (LinkedIn, and Meta through a Page that already has ads access) the call connects right away and answers already_connected: true, so read-only keys can't call it. OpenAI has no sign-in: POST /v1/connect/openai/ads with { "api_key": "..." } from ChatGPT Ads Manager.

Path parameters

networkstringrequired

meta, google, linkedin, tiktok or x.

Query parameters

return_tourl

Where the browser lands afterwards.

account_idstring

X or TikTok: the acc_ id of the posting account, when several are connected.

curl "https://creatoros-production-5658.up.railway.app/v1/connect/google/ads" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "network": "google",
  "auth_url": "https://accounts.google.com/o/oauth2/v2/auth?...",
  "already_connected": false
}

Connect OpenAI (ChatGPT) ads

POST/v1/connect/openai/ads

OpenAI has no sign-in step: create an API key in ChatGPT Ads Manager and send it here. One key connects exactly one ad account; sending a new key for the same account replaces the old one. A key OpenAI rejects returns 400 invalid_credentials. ChatGPT Ads Manager is open to US-based businesses, and ads show to ChatGPT Free and Go users in the US, Canada, Australia and New Zealand.

Body

api_keystringrequired

The OpenAI Ads API key. Stored server-side, never returned.

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/connect/openai/ads" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "sk-ads-..."
  }'
Response 201
{
  "network": "openai",
  "id": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
  "adAccountName": "Kev Builds Apps"
}

List ad connections

GET/v1/ads/connections

One per network login. Its id is the accountId every other ads call takes.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/connections" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "connections": [
    {
      "id": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
      "network": "meta",
      "displayName": "Kev Builds Apps",
      "isActive": true,
      "needsReconnection": false
    }
  ]
}

List ad accounts

GET/v1/ads/accounts

The ad accounts a connection can spend from, with currency, status and billing status.

Query parameters

accountIdstringrequired

An ad connection (acc_).

curl "https://creatoros-production-5658.up.railway.app/v1/ads/accounts?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "accounts": [
    {
      "adAccountId": "act_1234567890",
      "name": "Kev Builds Apps",
      "currency": "USD",
      "accountStatus": 1,
      "billingStatus": "ok"
    }
  ]
}

Campaigns, ad sets and ads

GET/v1/ads/tree

Every campaign with its ad sets and ads nested inside and spend, impressions, clicks, CTR, CPC and conversions rolled up at each level. The quickest way to answer "how are my ads doing".

Query parameters

platformstring

facebook, instagram, google, twitter or openai.

fromDateYYYY-MM-DD

Defaults to 90 days ago.

toDateYYYY-MM-DD

Defaults to today.

searchstring

Match campaign names.

pageinteger

From 1.

limitinteger

Campaigns per page.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/tree" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "campaigns": [
    {
      "platformCampaignId": "120210000000001",
      "platform": "facebook",
      "campaignName": "Spring launch",
      "status": "active",
      "currency": "USD",
      "metrics": {
        "spend": 142.5,
        "impressions": 38210,
        "clicks": 911,
        "ctr": 2.38
      },
      "adSets": [
        {
          "platformAdSetId": "120210000000002",
          "adSetName": "US 25-44",
          "ads": [
            {
              "id": "ad_7Qm2vK9xLp3TzR8wYc1NbF4h",
              "name": "Reel boost",
              "status": "active"
            }
          ]
        }
      ]
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 1,
    "pages": 1
  }
}

List campaigns

GET/v1/ads/campaigns

Flat campaign list with budget, status and metrics, filterable by network, status and ad account. Pass source=creatoros to list only campaigns made through Creator OS (the default all includes campaigns made in the networks' own dashboards).

Query parameters

platformstring

Network.

statusstring

Campaign status.

adAccountIdstring

One ad account.

fromDateYYYY-MM-DD

Metrics from.

toDateYYYY-MM-DD

Metrics to.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/campaigns" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "campaigns": [
    {
      "platformCampaignId": "120210000000001",
      "platform": "facebook",
      "campaignName": "Spring launch",
      "status": "active",
      "budget": {
        "amount": 20,
        "type": "daily"
      },
      "currency": "USD",
      "adCount": 2
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 1,
    "pages": 1
  }
}

Create a campaign

POST/v1/ads/campaigns

A campaign on its own, with no ad set or ad yet (add ads to it later with existingCampaignId on POST /v1/ads/create, Meta and Google). Google, X and OpenAI require a budget. validateOnly checks it without creating anything (Meta, OpenAI).

Body

accountIdstringrequired

The ad connection (acc_).

adAccountIdstringrequired

The ad account.

namestringrequired

Campaign name.

goalstringrequired

engagement, traffic, awareness, leads, conversions, ...

budgetobject

{ "amount": 20, "type": "daily" } in whole currency units.

statusstring

ACTIVE or PAUSED.

validateOnlyboolean

Dry run.

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/campaigns" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
    "adAccountId": "act_1234567890",
    "name": "Q4 retargeting",
    "goal": "traffic",
    "budget": {
      "amount": 30,
      "type": "daily"
    },
    "status": "PAUSED"
  }'
Response 201
{
  "campaign": {
    "platformCampaignId": "120210000000001",
    "platform": "facebook",
    "campaignName": "Q4 retargeting",
    "status": "paused"
  }
}

Update a campaign

PUT/v1/ads/campaigns/{campaignId}

Change a campaign's budget, bid strategy or name. Meta and Google: everything; OpenAI: budget only (a daily cap can't go back to lifetime); X: not supported, change budgets on the ad or line item instead. On Meta, a campaign-level budget (CBO) is edited here and an ad-set-level one on the ad set.

Path parameters

campaignIdstringrequired

The network campaign id (platformCampaignId).

Body

platformstringrequired

facebook, instagram, google, twitter or openai (campaign ids are only unique per network).

budgetobject

{ amount, type } in whole currency units.

bidStrategystring

e.g. LOWEST_COST_WITHOUT_CAP.

bidAmountnumber

Whole currency units.

namestring

New name (Meta).

curl -X PUT "https://creatoros-production-5658.up.railway.app/v1/ads/campaigns/120210000000001" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "facebook",
    "budget": {
      "amount": 40,
      "type": "daily"
    }
  }'
Response 200
{
  "success": true
}

Delete a campaign

DELETE/v1/ads/campaigns/{campaignId}

Deletes the campaign and everything in it on Meta and Google. Can't be undone; pause instead if the user may want it back.

Path parameters

campaignIdstringrequired

The network campaign id (platformCampaignId).

Body

platformstringrequired

facebook, instagram, google, twitter or openai (campaign ids are only unique per network).

curl -X DELETE "https://creatoros-production-5658.up.railway.app/v1/ads/campaigns/120210000000001" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "google"
  }'
Response 200
{
  "success": true
}

Pause or resume a campaign

PUT/v1/ads/campaigns/{campaignId}/status

Pauses or resumes the whole campaign, on every network. The response says how many objects changed and why any were skipped.

Path parameters

campaignIdstringrequired

The network campaign id.

Body

statusstringrequired

active or paused.

platformstringrequired

facebook, instagram, google, twitter or openai.

curl -X PUT "https://creatoros-production-5658.up.railway.app/v1/ads/campaigns/120210000000001/status" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "paused",
    "platform": "facebook"
  }'
Response 200
{
  "status": "paused",
  "updated": 1,
  "skipped": 0
}

Pause or resume many campaigns

POST/v1/ads/campaigns/bulk-status

Up to 50 campaigns in one call, across networks.

Body

statusstringrequired

active or paused.

campaignsobject[]required

[{ "campaignId": "...", "platform": "facebook" }, ...]

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/campaigns/bulk-status" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "paused",
    "campaigns": [
      {
        "campaignId": "120210000000001",
        "platform": "facebook"
      },
      {
        "campaignId": "21874412345",
        "platform": "google"
      }
    ]
  }'
Response 200
{
  "updated": 2,
  "skipped": 0
}

Campaign analytics

GET/v1/ads/campaigns/{campaignId}/analytics

The campaign's totals and daily series (spend, impressions, clicks, CTR, CPC, CPM, conversions, ROAS). Google also reports impression share.

Path parameters

campaignIdstringrequired

The network campaign id (platformCampaignId).

Query parameters

fromDateYYYY-MM-DD

From.

toDateYYYY-MM-DD

To.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/campaigns/120210000000001/analytics" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "campaign": {
    "platformCampaignId": "120210000000001",
    "campaignName": "Spring launch",
    "currency": "USD"
  },
  "analytics": {
    "summary": {
      "spend": 142.5,
      "impressions": 38210,
      "clicks": 911,
      "ctr": 2.38,
      "cpc": 0.16
    },
    "daily": [
      {
        "date": "2026-09-29",
        "spend": 20,
        "impressions": 5400,
        "clicks": 131
      }
    ]
  }
}

List ad sets

GET/v1/ads/ad-sets

The middle level: Meta ad sets, Google ad groups, X line items, OpenAI ad groups. Up to 500 rows.

Query parameters

accountIdstringrequired

The ad connection (acc_).

campaignIdstring

One campaign.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/ad-sets?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ&campaignId=120210000000001" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "adSets": [
    {
      "platformAdSetId": "120210000000002",
      "adSetName": "US 25-44",
      "status": "active",
      "budget": {
        "amount": 20,
        "type": "daily"
      },
      "adCount": 2
    }
  ]
}

Update an ad set

PUT/v1/ads/ad-sets/{adSetId}

Budget, bid strategy and (Meta) name of an ad set. PUT /v1/ads/ad-sets/{adSetId}/status with { "status": "paused" } pauses or resumes it on every network (on X that is the line item).

Path parameters

adSetIdstringrequired

The network ad set id (platformAdSetId).

Body

platformstringrequired

facebook, instagram, google, twitter or openai (campaign ids are only unique per network).

budgetobject

{ amount, type }.

bidStrategystring

Bid strategy.

bidAmountnumber

Whole currency units.

namestring

Meta only.

curl -X PUT "https://creatoros-production-5658.up.railway.app/v1/ads/ad-sets/120210000000002" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "facebook",
    "budget": {
      "amount": 25,
      "type": "daily"
    }
  }'
Response 200
{
  "success": true
}

Create an ad

POST/v1/ads/create

Campaign, ad set and ad in one call. Meta needs headline, body, linkUrl, imageUrl and callToAction; Google adds campaignType (search, display, pmax, demand_gen) and keywords; TikTok makes a video ad (the video URL goes in imageUrl, minimum budget $20); X makes a text post from body (280 characters); OpenAI needs headline (3 to 50), body (100), imageUrl and linkUrl, and targets countries only. Send an Idempotency-Key header to make retries safe. Send validateOnly: true first to check it without creating anything (see Validate before you create below).

Body

accountIdstringrequired

The ad connection (acc_).

adAccountIdstringrequired

From GET /v1/ads/accounts.

namestringrequired

Campaign name.

goalstringrequired

engagement, traffic, awareness, leads, conversions, video_views, app_promotion (per network).

budgetAmountnumberrequired

Whole currency units.

budgetTypestringrequired

daily or lifetime.

headlinestring

Headline.

bodystring

Primary text.

linkUrlurl

Destination.

imageUrlurl

Public image URL or med_ id.

callToActionstring

LEARN_MORE, SHOP_NOW, SIGN_UP, ...

countriesstring[]

ISO country codes.

startDateISO 8601

Start.

endDateISO 8601

Required for lifetime budgets.

statusstring

ACTIVE (default) or PAUSED to review first.

audienceIdstring

An aud_ id to target.

validateOnlyboolean

Check everything, create nothing. Returns 200 with valid and checks.

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/create" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
    "adAccountId": "act_1234567890",
    "name": "Spring launch",
    "goal": "traffic",
    "budgetAmount": 20,
    "budgetType": "daily",
    "headline": "Run your socials with AI",
    "body": "Post everywhere from one place.",
    "linkUrl": "https://www.creatoros.ca",
    "imageUrl": "https://example.com/ad.jpg",
    "callToAction": "LEARN_MORE",
    "countries": [
      "US"
    ],
    "status": "PAUSED"
  }'
Response 201
{
  "ad": {
    "id": "ad_7Qm2vK9xLp3TzR8wYc1NbF4h",
    "name": "Spring launch",
    "platform": "facebook",
    "status": "pending_review",
    "platformCampaignId": "120210000000001"
  },
  "message": "Ad created"
}

Boost a post

POST/v1/ads/boost

Promotes a post that is already published, keeping its likes and comments. Meta, Google, TikTok (as a Spark Ad, keeping the creator's identity) and X. On Meta, postId can be a post from GET /v1/ads/instagram-posts. Boosts can take minutes when Meta re-hosts a reel: don't retry on a timeout, send an Idempotency-Key. Send validateOnly: true first to check it without creating anything.

Body

postIdstringrequired

A post_ id (or platformPostId).

accountIdstringrequired

The ad connection (acc_).

adAccountIdstringrequired

The ad account.

budgetAmountnumberrequired

Whole currency units.

budgetTypestringrequired

daily or lifetime.

goalstring

engagement (default), traffic, awareness, ...

startDateISO 8601

Start.

endDateISO 8601

End.

targetingobject

{ countries, ageMin, ageMax, interests, ... }

validateOnlyboolean

Check everything, create nothing. Returns 200 with valid and checks.

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/boost" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "postId": "post_Ls8Qw2mV9kPz4TcY7rXn1BdH",
    "accountId": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
    "adAccountId": "act_1234567890",
    "budgetAmount": 15,
    "budgetType": "daily",
    "endDate": "2026-10-07T00:00:00Z",
    "targeting": {
      "countries": [
        "US",
        "CA"
      ]
    }
  }'
Response 201
{
  "ad": {
    "id": "ad_7Qm2vK9xLp3TzR8wYc1NbF4h",
    "name": "Boost: new reel",
    "status": "pending_review"
  },
  "message": "Boost created"
}

Validate before you create

POST/v1/ads/create

Add validateOnly: true to POST /v1/ads/create, /v1/ads/boost, /v1/ads/messaging or /v1/ads/call when the user (or the agent) is ready to submit. Nothing is created or charged. The answer is always 200 with valid, one line per check and a readable message; send the identical request without validateOnly to create it.

Creator OS checks first, on every network: required fields, goal, dates, the connection, the ad account's status, minimum daily budget, currency, the network's creative limits, and Meta's rule that a daily-budget ad runs at least 24 hours. When those pass, create also runs the network's own dry run on Meta, OpenAI and Google Performance Max (checked_by: "network"); boosts, TikTok and X have none, so Creator OS's checks are the whole answer. Meta counts its dry runs as writes (30 per ad account per 5 minutes), so validate once, when ready, not on every change.

Body

validateOnlybooleanrequired

true. Every other field is the normal create or boost body.

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/create" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "validateOnly": true,
    "accountId": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
    "adAccountId": "act_1234567890",
    "name": "Spring launch",
    "goal": "traffic",
    "budgetAmount": 20,
    "budgetType": "daily",
    "headline": "Run your socials with AI",
    "body": "Post everywhere from one place.",
    "linkUrl": "https://www.creatoros.ca",
    "imageUrl": "https://example.com/ad.jpg",
    "callToAction": "LEARN_MORE",
    "countries": [
      "US"
    ]
  }'
Response 200
{
  "validateOnly": true,
  "valid": false,
  "network": "meta",
  "checked_by": "creatoros",
  "checks": [
    {
      "check": "fields",
      "status": "passed",
      "message": "Every required field is there."
    },
    {
      "check": "ad_account",
      "status": "passed",
      "message": "Kev Studio (USD)."
    },
    {
      "check": "budget",
      "status": "failed",
      "message": "Below the minimum of 1.41 a day for this ad account."
    }
  ],
  "message": "Not ready: Below the minimum of 1.41 a day for this ad account."
}

List ads

GET/v1/ads

Individual ads with status (pending_review, active, paused, rejected, completed, cancelled, error), review status, budget, creative, targeting and metrics. Defaults to the last 90 days (up to 730). A 202 with backfillPending means a newly connected account is still importing its history.

Query parameters

platformstring

Network.

statusstring

pending_review, active, paused, rejected, completed, cancelled or error.

campaignIdstring

One campaign.

sourcestring

all (default) or creatoros for ads made through Creator OS.

curl "https://creatoros-production-5658.up.railway.app/v1/ads" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "ads": [
    {
      "id": "ad_7Qm2vK9xLp3TzR8wYc1NbF4h",
      "name": "Reel boost",
      "platform": "instagram",
      "status": "active",
      "adType": "boost",
      "budget": {
        "amount": 15,
        "type": "daily"
      },
      "metrics": {
        "spend": 48.2,
        "impressions": 12040,
        "clicks": 310
      }
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 1,
    "pages": 1
  }
}

Get an ad

GET/v1/ads/{adId}

One ad with its creative, targeting, schedule, budget and metrics. live=true re-reads it from the network instead of the last sync.

Path parameters

adIdstringrequired

The ad_ id.

Query parameters

liveboolean

Read fresh from the network.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/ad_7Qm2vK9xLp3TzR8wYc1NbF4h" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "ad": {
    "id": "ad_7Qm2vK9xLp3TzR8wYc1NbF4h",
    "name": "Reel boost",
    "platform": "instagram",
    "status": "active",
    "reviewStatus": "approved",
    "goal": "engagement",
    "budget": {
      "amount": 15,
      "type": "daily"
    },
    "platformCampaignId": "120210000000001",
    "metrics": {
      "spend": 48.2,
      "impressions": 12040,
      "clicks": 310
    }
  },
  "stale": false
}

Update an ad

PUT/v1/ads/{adId}

Status and budget everywhere. Meta also takes targeting, creative and name; Google takes targeting (keywords, locations, languages, devices) and headlines / descriptions / finalUrls. On X and OpenAI, creative or targeting changes return 501 unsupported_platform_operation: create a new ad instead.

Path parameters

adIdstringrequired

The ad_ id.

Body

statusstring

active or paused.

budgetobject

{ amount, type } in whole currency units.

targetingobject

Meta, Google.

creativeobject

Meta, Google.

namestring

Meta.

curl -X PUT "https://creatoros-production-5658.up.railway.app/v1/ads/ad_7Qm2vK9xLp3TzR8wYc1NbF4h" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "budget": {
      "amount": 25,
      "type": "daily"
    }
  }'
Response 200
{
  "ad": {
    "id": "ad_7Qm2vK9xLp3TzR8wYc1NbF4h",
    "budget": {
      "amount": 25,
      "type": "daily"
    }
  },
  "message": "Ad updated"
}

Cancel an ad

DELETE/v1/ads/{adId}

Stops the ad for good and marks it cancelled. On OpenAI this archives the ad, its ad group and its campaign. Pause instead if it may come back.

Path parameters

adIdstringrequired

The ad_ id.

curl -X DELETE "https://creatoros-production-5658.up.railway.app/v1/ads/ad_7Qm2vK9xLp3TzR8wYc1NbF4h" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "ad": {
    "id": "ad_7Qm2vK9xLp3TzR8wYc1NbF4h",
    "status": "cancelled"
  }
}

Pause or resume an ad

PUT/v1/ads/{adId}/status

On X this switches the line item the ad runs in.

Path parameters

adIdstringrequired

The ad_ id.

Body

statusstringrequired

active or paused.

curl -X PUT "https://creatoros-production-5658.up.railway.app/v1/ads/ad_7Qm2vK9xLp3TzR8wYc1NbF4h/status" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "paused"
  }'
Response 200
{
  "updated": true,
  "status": "paused"
}

Ad analytics

GET/v1/ads/{adId}/analytics

Summary and a day-by-day series: spend, impressions, reach, clicks, CTR, CPC, CPM, conversions, ROAS. breakdowns (age, gender, country, ...) on Meta. The campaign version is GET /v1/ads/campaigns/{campaignId}/analytics. OpenAI syncs once a day.

Path parameters

adIdstringrequired

The ad_ id.

Query parameters

fromDateYYYY-MM-DD

From.

toDateYYYY-MM-DD

To.

breakdownsstring

Meta only.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/ad_7Qm2vK9xLp3TzR8wYc1NbF4h/analytics" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "ad": {
    "id": "ad_7Qm2vK9xLp3TzR8wYc1NbF4h",
    "name": "Reel boost",
    "platform": "instagram",
    "currency": "USD"
  },
  "analytics": {
    "summary": {
      "spend": 48.2,
      "impressions": 12040,
      "clicks": 310,
      "ctr": 2.57,
      "cpc": 0.16
    },
    "daily": [
      {
        "date": "2026-09-29",
        "spend": 15,
        "impressions": 3900,
        "clicks": 101
      }
    ]
  }
}

Create an audience

POST/v1/ads/audiences

customer_list on Meta, Google, LinkedIn, TikTok and X (then add people to it); website (pixel visitors) and lookalike on Meta; saved_targeting stores a reusable targeting spec. OpenAI has no audiences. Target one on an ad with audienceId.

Body

accountIdstringrequired

The ad connection (acc_).

adAccountIdstringrequired

The ad account.

namestringrequired

Audience name.

typestringrequired

customer_list, website, lookalike or saved_targeting.

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/audiences" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
    "adAccountId": "act_1234567890",
    "name": "Newsletter subscribers",
    "type": "customer_list"
  }'
Response 201
{
  "audience": {
    "id": "aud_Pz3Lk8Qm2Vw9TcX4rY7nB1dH",
    "name": "Newsletter subscribers",
    "type": "customer_list"
  }
}

List audiences

GET/v1/ads/audiences

Audiences on an ad connection (Meta, Google, LinkedIn, TikTok, X).

Query parameters

accountIdstringrequired

The ad connection (acc_).

adAccountIdstring

One ad account.

typestring

customer_list, website, lookalike or saved_targeting.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/audiences?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "audiences": [
    {
      "id": "aud_Pz3Lk8Qm2Vw9TcX4rY7nB1dH",
      "name": "Newsletter subscribers",
      "type": "customer_list",
      "size": 4200
    }
  ]
}

Add people to an audience

POST/v1/ads/audiences/{audienceId}/users

Up to 10,000 people per call. Emails (and, on Meta, phone numbers) are SHA-256 hashed before they leave Creator OS's servers. Google and X match on email only; X needs at least 100 matched people before you can target the audience. GET, PUT and DELETE /v1/ads/audiences/{audienceId} read, rename and remove one.

Path parameters

audienceIdstringrequired

The aud_ id.

Body

usersobject[]required

[{ "email": "...", "phone": "..." }]

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/audiences/aud_Pz3Lk8Qm2Vw9TcX4rY7nB1dH/users" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "users": [
      {
        "email": "maya@example.com"
      },
      {
        "email": "sam@example.com"
      }
    ]
  }'
Response 200
{
  "success": true
}

Best posts to boost (Meta, TikTok)

GET/v1/ads/best-posts

Everything an ad connection can boost, in one ranked feed. Meta: the Instagram account its ads run as and the connected Facebook Page. TikTok: the linked TikTok account's videos, plus postingAccountId: boost one with POST /v1/ads/boost using that as accountId (a Spark Ad; the account must be an identity on the advertiser, see TikTok identities, or send a sparkAuthCode). Posts with engagement come first (likes and reactions, plus comments x2 and shares x3), the rest newest first. Instagram posts listed through an ad connection carry no counts from Meta; they get them when the same Instagram account is also connected for posting in the workspace. notes explains what's missing (e.g. an Instagram account that isn't linked to a Page the ad account can use). Pass a post's id to POST /v1/ads/boost as postId.

Query parameters

accountIdstringrequired

The Meta or TikTok ad connection (acc_).

adAccountIdstring

The ad account (act_... or the TikTok advertiser id).

curl "https://creatoros-production-5658.up.railway.app/v1/ads/best-posts?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ&adAccountId=act_1234567890" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "posts": [
    {
      "id": "post_Rk2mV8qL",
      "network": "instagram",
      "account": "@yourbrand",
      "caption": "How we doubled bookings in a month",
      "mediaType": "VIDEO",
      "thumbnailUrl": "https://...",
      "permalink": "https://www.instagram.com/reel/...",
      "publishedAt": "2026-09-21T18:02:11Z",
      "metrics": {
        "likes": 842,
        "comments": 96,
        "shares": 41,
        "reactions": 0
      },
      "score": 1157
    },
    {
      "id": "post_Tz4nB1hC",
      "network": "facebook",
      "account": "Your Brand",
      "caption": "New drop Friday",
      "mediaType": "image",
      "thumbnailUrl": "https://...",
      "permalink": "https://www.facebook.com/...",
      "publishedAt": "2026-09-18T15:00:00Z",
      "metrics": {
        "likes": 0,
        "comments": 12,
        "shares": 3,
        "reactions": 140
      },
      "score": 173
    }
  ],
  "sources": [
    {
      "network": "instagram",
      "account": "@yourbrand",
      "posts": 25,
      "metrics": true
    },
    {
      "network": "facebook",
      "account": "Your Brand",
      "posts": 25,
      "metrics": true
    }
  ],
  "notes": []
}

Instagram identities (Meta)

GET/v1/ads/instagram-accounts

The Instagram accounts a Meta ad account can run ads as: each Facebook Page with its linked Instagram account, and resolved, the identity ads use by default. An Instagram account only appears once it is linked to one of the connected Pages in Meta Business Suite.

Query parameters

accountIdstringrequired

The Meta ad connection (acc_).

adAccountIdstringrequired

The ad account (act_...).

curl "https://creatoros-production-5658.up.railway.app/v1/ads/instagram-accounts?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ&adAccountId=act_1234567890" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "accounts": [
    {
      "igUserId": "17841400000000000",
      "username": "yourbrand",
      "source": "page_backed"
    }
  ],
  "pages": [
    {
      "pageId": "123456789",
      "name": "Your Page",
      "instagramBusinessAccount": {
        "igUserId": "17841400000000000",
        "username": "yourbrand"
      }
    }
  ],
  "resolved": {
    "pageId": "123456789",
    "igUserId": "17841400000000000",
    "source": "page_backed"
  }
}

LinkedIn Company Pages

GET/v1/ads/linkedin-pages

The Company Pages the LinkedIn member behind the ad connection can run ads as. Pass one's organizationId on POST /v1/ads/create: the ad is a sponsored post from that Page (it never shows on the Page's own feed). The member must be an Administrator or Sponsored Content Poster of the Page, and the Page linked to the ad account.

Query parameters

accountIdstring

The LinkedIn ad connection (acc_); optional when there is one.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/linkedin-pages?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "pages": [
    {
      "organizationId": "urn:li:organization:105959150",
      "name": "Your Company",
      "vanityName": "yourcompany",
      "logoUrl": "https://..."
    }
  ],
  "postingAccountId": "acc_Tz4nB1hC...",
  "notes": []
}

LinkedIn suggested bid and budget

POST/v1/ads/targeting/bid-pricing

LinkedIn's suggested bid, allowed bid range and daily budget bounds for a targeting spec, before you create anything (nothing is created). dailyBudgetLimits.min is the real minimum for that audience. POST /v1/ads/targeting/supply-forecast takes the same spec plus a future window and a budget and projects impressions, clicks and spend. Other networks answer { "available": false }.

Body

accountIdstringrequired

The LinkedIn ad connection.

adAccountIdstringrequired

The LinkedIn ad account.

specobjectrequired

Targeting, the same shape as create: { countries, industries, seniorities, ... }.

bidTypestring

CPM (default), CPC or CPV.

objectiveTypestring

e.g. WEBSITE_VISIT, LEAD_GENERATION.

dailyBudgetnumber

Optional.

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/targeting/bid-pricing" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
    "adAccountId": "517258773",
    "spec": {
      "countries": [
        "US"
      ]
    },
    "bidType": "CPC",
    "objectiveType": "WEBSITE_VISIT",
    "currency": "USD"
  }'
Response 200
{
  "available": true,
  "pricing": {
    "bidLimits": {
      "min": {
        "amount": "2.00",
        "currencyCode": "USD"
      },
      "max": {
        "amount": "60.00",
        "currencyCode": "USD"
      }
    },
    "suggestedBid": {
      "min": {
        "amount": "5.10",
        "currencyCode": "USD"
      },
      "default": {
        "amount": "7.40",
        "currencyCode": "USD"
      },
      "max": {
        "amount": "11.20",
        "currencyCode": "USD"
      }
    },
    "dailyBudgetLimits": {
      "min": {
        "amount": "10.00",
        "currencyCode": "USD"
      }
    }
  }
}

Google Search keywords

GET/v1/ads/keywords

The keywords your Google Search campaigns run (positive and negative), synced about once a day, with Google's quality score (1 to 10) and trailing 30-day results. POST /v1/ads/keywords adds keywords to an ad group (adSetId, keywords, optional negative: true); PATCH / DELETE /v1/ads/keywords/{keywordId} pause or remove one.

Query parameters

accountIdstringrequired

The Google ad connection.

campaignIdstring

Only this campaign.

adSetIdstring

Only this ad group.

negativeboolean

true for negatives only.

searchstring

Text the keyword contains.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/keywords?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "keywords": [
    {
      "id": "66f2b3c4d5e6f7a8b9c0d1e2",
      "adSetId": "165489732105",
      "keyword": "social media scheduler",
      "matchType": "phrase",
      "status": "active",
      "negative": false,
      "qualityScore": 8,
      "metrics": {
        "spend": 140.2,
        "impressions": 4100,
        "clicks": 190,
        "conversions": 7
      }
    }
  ]
}

Google Keyword Planner ideas

POST/v1/ads/keywords/ideas

Keyword ideas from seed keywords and / or a landing page: average monthly searches, competition and the top-of-page bid range. Counters are strings and bids are in micros (divide by 1,000,000). POST /v1/ads/keywords/historical-metrics returns the same metrics for keywords you already have.

Body

accountIdstringrequired

The Google ad connection.

seedKeywordsstring[]

Seed keywords.

seedUrlurl

A landing page.

countriesstring[]

Omit for worldwide.

customerIdstring

When the login reaches several Google Ads accounts.

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/keywords/ideas" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
    "seedKeywords": [
      "social media scheduler"
    ],
    "seedUrl": "https://www.example.com",
    "countries": [
      "US"
    ]
  }'
Response 200
{
  "customerId": "1234567890",
  "data": [
    {
      "text": "social media scheduler",
      "keywordIdeaMetrics": {
        "avgMonthlySearches": "9900",
        "competition": "HIGH",
        "lowTopOfPageBidMicros": "2100000",
        "highTopOfPageBidMicros": "9800000"
      }
    }
  ],
  "paging": {
    "nextPageToken": null
  }
}

Google search terms

GET/v1/ads/search-terms

The searches that actually triggered your Google Search ads, by cost (last 30 days by default), and whether each is already a keyword (ADDED), a negative (EXCLUDED) or new (NONE): the input for negative keywords and new keywords. Cost is in micros.

Query parameters

accountIdstringrequired

The Google ad connection.

fromDatedate

YYYY-MM-DD.

toDatedate

YYYY-MM-DD.

campaignIdstring

Only this campaign.

customerIdstring

When the login reaches several accounts.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/search-terms?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "customerId": "1234567890",
  "data": [
    {
      "searchTerm": "best social media scheduler",
      "status": "NONE",
      "campaignName": "Search",
      "impressions": 340,
      "clicks": 21,
      "costMicros": 18400000,
      "conversions": 1
    }
  ],
  "stale": false
}

Google recommendations

GET/v1/ads/recommendations

Google's optimization suggestions (budgets, bidding, keywords, ad text) with its estimated impact (base today vs potential after). Apply with POST /v1/ads/recommendations/apply ({ accountId, adAccountId, recommendations: [{ resourceName }] }; it changes the account and can't be undone) or dismiss with POST /v1/ads/recommendations/dismiss (resourceNames). Both run per item: check each result's status.

Query parameters

accountIdstringrequired

The Google ad connection.

adAccountIdstringrequired

The customer id.

typesstring

e.g. CAMPAIGN_BUDGET,KEYWORD.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/recommendations?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ&adAccountId=1234567890" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "adAccountId": "1234567890",
  "recommendations": [
    {
      "resourceName": "customers/1234567890/recommendations/Njgz...",
      "type": "CAMPAIGN_BUDGET",
      "campaignId": "21874563210",
      "impact": {
        "base": {
          "clicks": 87,
          "cost": 420
        },
        "potential": {
          "clicks": 185,
          "cost": 889.58
        }
      }
    }
  ],
  "stale": false
}

TikTok identities

GET/v1/ads/tiktok-identities

Who TikTok ads on an advertiser can run as (the profile shown on the ad): the advertiser's own TikTok accounts (TT_USER), Business Center accounts (BC_AUTH_TT) and brand identities (CUSTOMIZED_USER). Pass one as identityId + identityType on POST /v1/ads/create. A Spark boost only works on videos whose owner is listed here, unless it carries a sparkAuthCode; validateOnly warns when it isn't.

Query parameters

accountIdstringrequired

The TikTok ad connection (acc_).

adAccountIdstringrequired

The TikTok advertiser id.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/tiktok-identities?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ&adAccountId=7123456789012345678" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "adAccountId": "7123456789012345678",
  "identities": [
    {
      "identityId": "d2fd1f9b-6f00-4a40-b2ff-c8413888db87",
      "identityType": "TT_USER",
      "displayName": "yourbrand",
      "username": "yourbrand",
      "profileImage": "https://..."
    }
  ]
}

Search targeting

GET/v1/ads/targeting/search

Look up location, interest, behavior and language ids to target.

Query parameters

accountIdstringrequired

The ad connection.

qstringrequired

Search text.

dimensionstring

geo, interest, behavior, language, ...

curl "https://creatoros-production-5658.up.railway.app/v1/ads/targeting/search?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ&q=fitness&dimension=interest" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "results": [
    {
      "id": "6003107902433",
      "name": "Physical fitness",
      "audienceSize": 480000000
    }
  ]
}

Send conversions

POST/v1/ads/conversions

Server-side conversion events (purchases, leads, sign-ups) for Meta, Google and OpenAI, so the networks can optimize and report results. destinationId is the Meta pixel id, the Google conversion action or the OpenAI pixel. Not available on X.

Body

accountIdstringrequired

The ad connection (acc_).

destinationIdstringrequired

Pixel or conversion action.

eventsobject[]required

[{ eventName, eventTime, value, currency, user: { email } }]

curl -X POST "https://creatoros-production-5658.up.railway.app/v1/ads/conversions" \
  -H "Authorization: Bearer $CREATOROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "accountId": "acc_Hq4mP8sVw2LkT9xZr6YbN3cJ",
    "destinationId": "1234567890",
    "events": [
      {
        "eventName": "Purchase",
        "eventTime": "2026-09-29T18:04:00Z",
        "value": 49,
        "currency": "USD",
        "user": {
          "email": "maya@example.com"
        }
      }
    ]
  }'
Response 200
{
  "success": true
}

Live insights query

GET/v1/ads/insights

For questions the synced metrics can't answer. Meta: pass objectId (an ad account, campaign, ad set or ad) with fields, breakdowns and filtering. Google: pass a read-only GAQL query (money in micros; a segments.date select needs a finite range). LinkedIn's who-saw-it splits are on GET /v1/ads/campaigns/{campaignId}/analytics?breakdowns=seniority,industry,company_size,job_function. TikTok: pass adAccountId, dataLevel (AUCTION_ADVERTISER, _CAMPAIGN, _ADGROUP or _AD), dimensions (e.g. stat_time_day, at most 30 days per query; with reportType=AUDIENCE: age, gender, country_code, platform), metrics, fromDate and toDate; rows come back as { dimensions, metrics } with string values. Not available on X or OpenAI.

Query parameters

accountIdstringrequired

The ad connection (acc_).

objectIdstring

Meta object id.

fieldsstring

Meta fields, comma separated.

breakdownsstring

Meta breakdowns.

querystring

Google GAQL.

dataLevelstring

TikTok report level.

dimensionsstring

TikTok dimensions (1 to 4).

metricsstring

TikTok metrics, e.g. spend,impressions,clicks,reach,conversion.

curl "https://creatoros-production-5658.up.railway.app/v1/ads/insights?accountId=acc_Hq4mP8sVw2LkT9xZr6YbN3cJ&objectId=act_1234567890&fields=spend%2Cimpressions%2Cactions" \
  -H "Authorization: Bearer $CREATOROS_API_KEY"
Response 200
{
  "data": [
    {
      "spend": "142.50",
      "impressions": "38210",
      "actions": [
        {
          "action_type": "link_click",
          "value": "911"
        }
      ]
    }
  ]
}