Campaign Management API (Closed Beta)
The Campaign Management API is currently in closed beta and available to select customers. We are continuing to enhance features and performance ahead of general availability. As this API is in beta, certain functionality and limits may evolve. If interested, please contact your Account Manager to learn more.
The Campaign Management API allows you to programmatically manage your campaigns and creatives. With the Campaign Management API, you can:
- Launch UA expansion campaigns
- Manage campaign spend and certain targeting settings
- Upload assets and assemble creatives
- Manage creative state and attachment
Authentication
The API uses HTTP Basic authentication. To authenticate, send your API token in the Authorization header as a base64-encoded string. For example:
Authorization: Basic <base64(ApiKey:ApiSecret)>
- ApiKey is your Liftoff API Key
- ApiSecret is your Liftoff API Secret
- The value is the Base64 encoding of the string ApiKey:ApiSecret
API structure
You can explore all available endpoints in the API Reference and Sandbox. All API URLs start with https://cm-api.liftoff.io/v1, use standard REST patterns, and return JSON. Different endpoints can be called by appending to the base url. Available endpoints are described in the table below:
| Endpoints | Description |
|---|---|
| /apps | Retrieve app list and metadata |
| /assets | Upload and manage assets |
| /creatives | Assemble creatives |
| /campaigns | Retrieve, create, and modify campaigns |
Rate limits and quotas
| Quota | Limit |
|---|---|
| Requests per minute per REST method | 1,000 |
| Max campaigns enabled at one time | 100 |
| Max enabled creatives per campaign | 100 |
| Max creatives assembled daily | 1,500 |
| Max assets uploaded daily | 1,500 |
Error handling
The API uses standard HTTP status codes.
| Error code | Description |
|---|---|
| 400 | Bad Request |
| 401 | Missing or Invalid API Key |
| 403 | Access Denied |
| 404 | Not Found |
| 429 | Too Many Requests |
| 500 | Server Error |
| 503 | Service Unavailable |
Sample workflows: Creating campaigns
Before you start, explore the various entities associated with your account via the following endpoints.
| Entities | URL |
|---|---|
| Apps | https://cm-api.liftoff.io/v1/apps |
| Campaigns | https://cm-api.liftoff.io/v1/campaigns |
| Creatives | https://cm-api.liftoff.io/v1/creatives |
| Events | https://cm-api.liftoff.io/v1/apps/{appId}/events |
| Audiences | https://cm-api.liftoff.io/v1/audiences |
Follow this sequence to launch your campaign. Only UA expansion campaigns are currently supported.
- Upload assets
- Assemble creatives
- Create a campaign
- Attach the creatives to the campaign
- Enable the campaign
- Upload assets
Begin by uploading the media files (images or videos) you want to use in your creatives. Each uploaded asset receives a unique assetId, which is later referenced when assembling creatives.
- You can upload up to 1,500 assets daily
- Maximum file size for image is 10MB
- Maximum video duration is 180 seconds
- You are required to disclose realistic content that was generated with AI. Set
aiDeclaredtotrueto label such content (defaults tofalseif omitted) - Supported file types:
- Images: JPEG, PNG, WebP, GIF
- Videos: MP4, QuickTime (MOV), WebM
Example:
POST /v1/assets
curl -X POST 'https://cm-api.liftoff.io/v1/assets' \
-u 'API_KEY:API_SECRET' \
-H 'Accept: application/json' \
-F 'file=@/dir/test.mp4;type=video/mp4;filename=test.mp4' \
-F 'aiDeclared=true'
Response:
{
"id": "123abc",
"mediaType": "video",
"publicUrl": "https://cdn.liftoff.io/assets/ast_123.video",
"name": "ast_123.video"
}
- Assemble creatives
You can assemble creatives using uploaded assets. Each creative ties an asset ID to metadata. All creative types require the following information, and some fields are specific to their creative type. Please view the API Reference for more details.
- A maximum of 1,500 creatives can be assembled daily
- Required for all creatives: app ID, name, status, creative type, ad slot size, language
- VAST creatives
- Video asset ID
- Endcard asset ID
- Native creatives
- Image asset ID
- Title
- Description
- Optional: icon asset ID, CTA text translation
- Image creatives
- Image asset ID
- VAST creatives
Example:
Note that the following example shows the request and response when creating a VAST creative. Please refer to the NewCreativeBodyGeneral section of the API Reference for more details.
POST /v1/creatives
{
"name": "SpringSale",
"status": "PAUSED",
"language": "en",
"creativeType": "vast",
"adSlotSize": "320x480",
"videoAssetId": "ast_123",
"endcardAssetId": "ast_456",
"appId": "app_abc"
}
curl -X 'POST' \
'https://cm-api.liftoff.io/v1/creatives' \
-u 'API_KEY:API_SECRET' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"appId": "app_abc",
"name": "SpringSale",
"status": "PAUSED",
"language": "en",
"creativeType": "vast",
"adSlotSize": "320x480",
"videoAssetId": "ast_123",
"endcardAssetId": "ast_456"
}'
Response:
{
"creatives": [
{
"id": "123456",
"name": "SpringSale",
"status": "PAUSED",
"creativeType": "vast",
"createdAt": "2025-09-27T22:10:43.034Z",
"language": "en",
"adSlotSize": "320x480",
"vast": [
{
"videoAssetId": "ast_123",
"endcardHtmlAssetId": null,
"endcardImageAssetId": "ast_456"
}
],
"previewLink": "https://tre-preview.liftoff.io/preview/index.html?vm=true&creative=123456"
}
]
}
Ad slot sizes are required to assemble creatives. Declare the ad slot size to include Liftoff tablet or phone sizes:
| Device | Placements | Orientation | Ad slot size |
|---|---|---|---|
| Phone | Full-screen (Image and video) | Portrait | 320 x 480 |
| Landscape | 480 x 320 | ||
| Half-screen (Image and Video) | 300 x 250 | ||
| Banner (Image) | 320 x 50 | ||
| Tablet | Full-screen (Image and video) | Portrait | 768 x 1024 |
| Landscape | 1024 x 768 | ||
| Banner (Image) | 728 x 90 | ||
| Native (Image) | 1200 x 627 | ||
- Create a campaign
Next, create the UA campaign that will host your creatives. Campaigns are created in a paused state by default.
- You must provide the following fields: appId, clickTrackingUrl, spendCap, optimizationGoal, goalValue, and targeting.
- Campaign budgets are set in USD, with daily limits and constraints (budget changes allowed only 3× per day, within ±50%)
- A maximum of 100 campaigns can be enabled at once
- Must have a daily spend target ≥ $500
- Goal values are only for reference and do not affect performance or optimization
Example:
POST /v1/campaigns
{
"appId": "app_abc",
"name": "UA_Q2_CPI",
"spendCap": 5000,
"optimizationGoal": "CPA",
"goalValue": 2.50,
"optimizationFinalEventId": "12345",
"demandProduct": "accelerate",
"minOsVersion": "12.1.3",
"clickTrackingUrl": "https://example.tracker.com/id12345?&c=${CAMPAIGN_NAME}&siteid=${APP_ID}&ad=${CREATIVE_NAME}&c_id=${CAMPAIGN_EXTERNAL_ID}&ad_id=${CREATIVE_EXTERNAL_ID}&click_lookback=7d&clickid=${TRACKING_TOKEN}&idfa=${IDFA}&sha1_idfa=${IDFA_SHA1}&ip=${DEVICE_IP}&ua=${DEVICE_USER_AGENT}&channel=${DEMAND_PRODUCT}&lang=${DEVICE_LANGUAGE}&os_version=${DEVICE_OS_VERSION}&model=${DEVICE_MODEL}",
"pacingType": "daily",
"targeting": {
"countries": ["US", "CA"],
"devices": ["mobile"],
"excludedAudienceIds": ["A54BE3F"],
"includedAudienceIds": ["B2D4F1D"]
}
}
curl -X 'POST' \
'https://cm-api.liftoff.io/v1/campaigns' \
-u 'API_KEY:API_SECRET' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"appId": "app_abc",
"name": "UA_Q2_CPI",
"spendCap": 5000,
"optimizationGoal": "CPA",
"goalValue": 2.50,
"optimizationFinalEventId": "12345",
"demandProduct": "accelerate",
"minOsVersion": "12.1.3",
"clickTrackingUrl": "https://example.tracker.com/id12345?&c=${CAMPAIGN_NAME}&siteid=${APP_ID}&ad=${CREATIVE_NAME}&c_id=${CAMPAIGN_EXTERNAL_ID}&ad_id=${CREATIVE_EXTERNAL_ID}&click_lookback=7d&clickid=${TRACKING_TOKEN}&idfa=${IDFA}&sha1_idfa=${IDFA_SHA1}&ip=${DEVICE_IP}&ua=${DEVICE_USER_AGENT}&channel=${DEMAND_PRODUCT}&lang=${DEVICE_LANGUAGE}&os_version=${DEVICE_OS_VERSION}&model=${DEVICE_MODEL}",
"pacingType": "daily",
"targeting": {
"countries": ["US", "CA"],
"devices": ["mobile"],
"excludedAudienceIds": ["A54BE3F"],
"includedAudienceIds": ["B2D4F1D"]
}
}'
Response:
{
"id": "asd123"
}
- Attach the creatives to the campaign
Once your campaign is created, you can attach your creatives.
- Minimum of 1 enabled creative to deliver
- Maximum of 100 enabled creatives per campaign
- Note that adding a new creative format to an enabled campaign may affect available inventory and delivery behavior as the system adjusts to the updated targeting.
Example:
POST /v1/campaigns/{campaignId}/creatives/add
{
"creativeId": "123abc"
}
curl -X 'POST' \
'https://cm-api.liftoff.io/v1/campaigns/{campaignId}/creatives/add' \
-u 'API_KEY:API_SECRET' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"creativeId": "123abc"}'
- Enable the campaign
Finally, set the campaign status to enabled.
- Must have a daily spend target ≥ $500
- Must have ≥ 1 enabled creative attached
Example:
POST /v1/campaigns/{campaignId}/status
{
"status": "ENABLED"
}
curl -X 'POST' \
'https://cm-api.liftoff.io/v1/campaigns/{campaignId}/status' \
-u 'API_KEY:API_SECRET' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"status": "ENABLED"}'
Examples: Editing campaign spend
- Must have a daily spend target ≥ $500.
- Spend targets can only be changed 3 times within a 24 hour period.
- Each of these spend changes must be +/- 50% of the previous value to protect pacing.
- Changes can only be made within the first 12 hours of the day based on your billing timezone, as large or frequent spend changes may impact pacing and delivery for the remainder of the day.
Update spend targets
Example:
POST /v1/campaigns/{campaignId}/spendCaps/daily
{
"value": 7500
}
Schedule future spend changes
Scheduled changes will apply at midnight on the specified date based on your billing timezone.
Example:
POST /v1/campaigns/{campaignId}/spendCaps/schedule
{
"date": "2026-03-01",
"value": 10000
}
Cancel scheduled spend changes
Example:
POST /v1/campaigns/{campaignId}/spendCaps/cancel
{
"date": "2026-03-01",
"after": false
}
Examples: Editing campaign state
You can pause or enable campaigns using the endpoint below. To verify correct settings, you cannot enable campaigns that have been paused for more than 30 days; to adjust those, reach out to your Account Manager.
Endpoint: POST /v1/campaigns/{campaignId}/status
Example:
POST /v1/campaigns/{campaignId}/status
{
"status": "ENABLED"
}
Examples: Editing campaign targeting
This section walks through how to edit settings for existing campaigns using the POST /v1/campaigns/{campaignId} endpoint. This endpoint works similarly to the campaign creation endpoint in terms of the data it takes in the request body. The only difference is that a campaign ID needs to be provided in the URL, and only the following settings can be edited.
When targeting settings are updated, pacing may temporarily adjust as the system optimizes to the new configuration to best deliver performance. While delivery typically stabilizes within a few hours, to minimize variability, we recommend making changes earlier in the day.
Settings
- Optimization goal: which metric the campaign optimizes for
- Optimization final event ID: the target event for CPA campaigns
- Goal value: the value associated with the optimization goal
- Country: which countries the campaign is targeting
Optimization goal, values, and final event
- optimizationGoal
- Decides which metric the campaign optimizes for
- Possible values: CPI, CPA, ROAS
- When using CPA, an optimizationFinalEventId must also be added
- The target event that the campaign is optimizing towards
- Changes to optimization goals or final event selection may impact delivery behavior as the system adjusts to the updated objective
- goalValue
- The value associated with the optimization goal
- Informational only and does not affect campaign optimization or performance
- For CPA and CPI goals, the target value is in USD
- For ROAS goals the target value is % return
| Field | Type | Allowed values | Example |
|---|---|---|---|
| optimizationGoal | string | CPI, CPA, ROAS | CPI |
| goalValue | number | - | 5.5 |
| optimizationFinalEventId | string | - | 3082534 |
Example:
POST /v1/campaigns/{campaignId}
{
"optimizationGoal": "CPA",
"goalValue": 7.3,
"optimizationFinalEventId": "a1b2c3"
}
Country targeting
- Which countries the campaign is targeting
- Note that expanding or narrowing targeting may affect available inventory and delivery behavior as the system adjusts to the updated targeting
| Field | Type | Allowed values | Example |
|---|---|---|---|
| countries | string[] | List of two-letter country codes | US, CA |
Example of updating the targeted country:
POST /v1/campaigns/{campaignId}
{
"targeting": { "countries": ["US", "CA"] }
}
Frequently Asked Questions
Documentation
- What resources are available to help my team integrate? This Help Center page covers full feature documentation, rate limits, and quotas. The API Reference documents all available endpoints. The one-pager summarizes currently available beta features.
Creatives & Assets
- If I pause a creative, does it pause across all campaigns or just one? Pausing a creative via the
POST /creatives/{creativeID}/statusendpoint pauses it globally, across all campaigns it's attached to. If you only want to remove it from a specific campaign, use thePOST /campaigns/{campaignId}/creatives/removeendpoint instead. - Why might I be unable to pause a creative via the API? Similar to existing restrictions via the Creative Manager, there are two scenarios where pausing a creative will be blocked: (1) it is the top-spending creative on a campaign, or (2) it is the only enabled creative attached to a campaign. In both cases, you'll receive an error explaining why the action failed. To work around the first case, reach out to your Account Manager for support and options. For the second, you'll need to attach and enable another creative before pausing the existing one.
- What’s the difference between creative status via the API vs. creative status in the Creative Manager UI? The API response will return creatives as either enabled or paused. The Creative Manager UI provides additional information by displaying creatives as either active, queued, or paused - both active and queued creatives are considered enabled. Active creatives are live and spending, while queued creatives are enabled but not spending yet. The queue manages how many new creatives enter testing at once, so each one gets a fair opportunity to be tested. Once a slot opens, your creative will automatically move into delivery and begin spending.
- Can I use custom parameters (e.g. deep links) in creative uploads? Custom creative parameters such as deep links are not currently supported. If your setup requires this, please raise it with your Account Manager so it can be tracked as a feature request.
- Should I reuse existing assets or upload the same file multiple times? We recommend reusing existing assets rather than uploading the same file more than once. When you upload an asset, save the
assetIdfrom the response; you can reference it across multiple creatives without uploading again. This also helps you stay within the 1,500 asset upload limit per day.
Campaigns
- What is the minimum daily spend to launch a campaign via API? The minimum daily spend threshold is $500 per campaign. Please speak with your Account Manager to understand the requirements for your account.
- Can I re-enable a campaign that has been paused for a long time? Campaigns that have been paused for more than 30 days cannot be re-enabled via the API. To re-launch a campaign, contact your Account Manager.
- How long are campaigns with no spend retained in the API? Campaigns are not removed based on spend inactivity. A campaign paused for over 30 days will still be visible, but cannot be re-enabled via the API for safety reasons.
- How can I know if an event is ready to be set as the final optimization event for campaigns on CPA optimization? You can query
GET /apps/{appId}/events?campaignType=UAwhich will return"isCpaReady": truefor events that are ready. You will not be able to set events as final events if they are unready in order to prevent suboptimal performance and pacing.
Rate Limits
- What are the rate limits and why do they exist? Rate limits cap how many times your system can call the API within a given time window. They protect system stability and ensure consistent performance for all customers. The current limit is 1,000 requests per minute per API method (e.g. getting a list of campaigns counts as one method; updating a spend target is another).
- What happens if I hit a rate limit? You'll receive a
429 Too Many Requestserror. The response includes aRetry-Afterheader indicating when you can try again. If you're frequently hitting limits, consider caching campaign data on your end rather than re-fetching it on every request, and use bulk endpoints where available. Bulk endpoints are available to get creative, asset, and spend target data.
Spend Changes
- Are there restrictions on how often I can change campaign spend? Yes. Spend targets can only be changed 3 times within a 24-hour period, changes must be within ±50% of the current active daily budget, and changes can only be made within the first 12 hours of your billing timezone day.
Click here for a Chinese version of this FAQ.
Support
Please contact your Liftoff account team if you have feedback or need support.