Skip to main content
POST
/
ad_groups
Create an Ad Group
curl --request POST \
  --url https://api.whop.com/api/v1/ad_groups \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "ad_campaign_id": "<string>",
  "audiences": {},
  "budget_amount": 123,
  "demographics": {},
  "desired_cost_per_result": 123,
  "devices": {},
  "dynamic_creative": true,
  "ends_at": "<string>",
  "frequency_cap": {},
  "languages": [
    "<string>"
  ],
  "message_apps": [],
  "minimum_daily_spend": 123,
  "optimization_goal": "<string>",
  "placements": "<unknown>",
  "regions": {},
  "starts_at": "<string>",
  "title": "<string>"
}
'
import requests

url = "https://api.whop.com/api/v1/ad_groups"

payload = {
"ad_campaign_id": "<string>",
"audiences": {},
"budget_amount": 123,
"demographics": {},
"desired_cost_per_result": 123,
"devices": {},
"dynamic_creative": True,
"ends_at": "<string>",
"frequency_cap": {},
"languages": ["<string>"],
"message_apps": [],
"minimum_daily_spend": 123,
"optimization_goal": "<string>",
"placements": "<unknown>",
"regions": {},
"starts_at": "<string>",
"title": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
ad_campaign_id: '<string>',
audiences: {},
budget_amount: 123,
demographics: {},
desired_cost_per_result: 123,
devices: {},
dynamic_creative: true,
ends_at: '<string>',
frequency_cap: {},
languages: ['<string>'],
message_apps: [],
minimum_daily_spend: 123,
optimization_goal: '<string>',
placements: '<unknown>',
regions: {},
starts_at: '<string>',
title: '<string>'
})
};

fetch('https://api.whop.com/api/v1/ad_groups', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://api.whop.com/api/v1/ad_groups",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ad_campaign_id' => '<string>',
'audiences' => [

],
'budget_amount' => 123,
'demographics' => [

],
'desired_cost_per_result' => 123,
'devices' => [

],
'dynamic_creative' => true,
'ends_at' => '<string>',
'frequency_cap' => [

],
'languages' => [
'<string>'
],
'message_apps' => [

],
'minimum_daily_spend' => 123,
'optimization_goal' => '<string>',
'placements' => '<unknown>',
'regions' => [

],
'starts_at' => '<string>',
'title' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main

import (
"fmt"
"strings"
"net/http"
"io"
)

func main() {

url := "https://api.whop.com/api/v1/ad_groups"

payload := strings.NewReader("{\n \"ad_campaign_id\": \"<string>\",\n \"audiences\": {},\n \"budget_amount\": 123,\n \"demographics\": {},\n \"desired_cost_per_result\": 123,\n \"devices\": {},\n \"dynamic_creative\": true,\n \"ends_at\": \"<string>\",\n \"frequency_cap\": {},\n \"languages\": [\n \"<string>\"\n ],\n \"message_apps\": [],\n \"minimum_daily_spend\": 123,\n \"optimization_goal\": \"<string>\",\n \"placements\": \"<unknown>\",\n \"regions\": {},\n \"starts_at\": \"<string>\",\n \"title\": \"<string>\"\n}")

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://api.whop.com/api/v1/ad_groups")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"ad_campaign_id\": \"<string>\",\n \"audiences\": {},\n \"budget_amount\": 123,\n \"demographics\": {},\n \"desired_cost_per_result\": 123,\n \"devices\": {},\n \"dynamic_creative\": true,\n \"ends_at\": \"<string>\",\n \"frequency_cap\": {},\n \"languages\": [\n \"<string>\"\n ],\n \"message_apps\": [],\n \"minimum_daily_spend\": 123,\n \"optimization_goal\": \"<string>\",\n \"placements\": \"<unknown>\",\n \"regions\": {},\n \"starts_at\": \"<string>\",\n \"title\": \"<string>\"\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://api.whop.com/api/v1/ad_groups")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"ad_campaign_id\": \"<string>\",\n \"audiences\": {},\n \"budget_amount\": 123,\n \"demographics\": {},\n \"desired_cost_per_result\": 123,\n \"devices\": {},\n \"dynamic_creative\": true,\n \"ends_at\": \"<string>\",\n \"frequency_cap\": {},\n \"languages\": [\n \"<string>\"\n ],\n \"message_apps\": [],\n \"minimum_daily_spend\": 123,\n \"optimization_goal\": \"<string>\",\n \"placements\": \"<unknown>\",\n \"regions\": {},\n \"starts_at\": \"<string>\",\n \"title\": \"<string>\"\n}"

response = http.request(request)
puts response.read_body
{
  "ad_campaign": {
    "id": "<string>"
  },
  "added_to_carts": 123,
  "audiences": {},
  "bid_type": "minimum_cost",
  "budget_amount": 123,
  "budget_type": "daily",
  "click_through_rate": 123,
  "clicks": 123,
  "completed_registrations": 123,
  "contacts": 123,
  "conversion_location": "website",
  "cost_per_added_to_cart": 123,
  "cost_per_click": 123,
  "cost_per_completed_registration": 123,
  "cost_per_contact": 123,
  "cost_per_lead": 123,
  "cost_per_mille": 123,
  "cost_per_purchase": 123,
  "cost_per_result": 123,
  "cost_per_schedule": 123,
  "cost_per_submitted_application": 123,
  "cost_per_viewed_content": 123,
  "created_at": "<string>",
  "custom_conversions": 123,
  "delivery_status": "all_ads_rejected",
  "demographics": {},
  "desired_cost_per_result": 123,
  "devices": {},
  "dynamic_creative": true,
  "ends_at": "<string>",
  "frequency": 123,
  "frequency_cap": {},
  "id": "<string>",
  "impressions": 123,
  "issues": [
    {
      "id": "<string>",
      "message": "<string>",
      "resource_id": "<string>",
      "resource_type": "ad_campaign"
    }
  ],
  "languages": [
    "<string>"
  ],
  "leads": 123,
  "message_apps": [
    "<string>"
  ],
  "minimum_daily_spend": 123,
  "optimization_goal": "<string>",
  "placements": [
    {}
  ],
  "purchase_value": 123,
  "purchases": 123,
  "reach": 123,
  "regions": {},
  "result_event": "purchase",
  "result_event_name": "<string>",
  "return_on_ad_spend": 123,
  "schedules": 123,
  "spend": 123,
  "spend_currency": "<string>",
  "starts_at": "<string>",
  "status": "active",
  "submitted_applications": 123,
  "title": "<string>",
  "unique_click_through_rate": 123,
  "unique_clicks": 123,
  "updated_at": "<string>",
  "viewed_contents": 123
}
{
"error": {
"message": "<string>",
"type": "<string>"
}
}

Authorizations

Authorization
string
header
required

A company API key, company scoped JWT, app API key, or user OAuth token. You must prepend your key/token with the word 'Bearer', which will look like Bearer ***************************

Headers

Api-Version-Date
string

Pins the request to a dated API version.

Example:

"2026-07-08-1"

Body

application/json
ad_campaign_id
string
required

The ad campaign to create the ad group in.

audiences
object

Saved-audience targeting: { include, exclude } arrays of audience IDs. Incompatible with demographics.automatic (Advantage+).

bid_type
enum<string>

Bid strategy.

Available options:
minimum_cost,
average_target,
maximum_target
budget_amount
number

Ad-set budget in dollars (ABO only; omit under CBO).

budget_type
enum<string>

Whether the budget is daily or lifetime.

Available options:
daily,
lifetime
conversion_event

The pixel event optimized for. A standard event, or any custom pixel event name.

Available options:
purchase,
add_to_cart,
initiated_checkout,
add_payment_info,
complete_registration,
lead,
content_view,
search,
contact,
customize_product,
donate,
find_location,
schedule,
start_trial,
submit_application,
subscribe
conversion_location
enum<string>

Where results happen: website (conversions), profile (IG/FB engagement), messaging (DM), on_ad (engagement on the ad, surface follows the optimization goal), or the lead destinations (instant_forms, instant_forms_and_messenger, website_and_instant_forms). The lead form itself is set on the ad.

Available options:
website,
profile,
messaging,
on_ad,
instant_forms,
instant_forms_and_messenger,
website_and_instant_forms
demographics
object

Demographic targeting: { automatic, minimum_age, maximum_age, gender }.

desired_cost_per_result
number

Target/cap cost for average_target / maximum_target.

devices
object

Device targeting: { platforms, operating_systems: [{ os, minimum_version }] }.

dynamic_creative
boolean

Run Meta dynamic (Advantage+) creative for this ad set. Set at creation; immutable afterward.

ends_at
string

Schedule end, ISO 8601.

frequency_cap
object

{ maximum_impressions, per_days } — only valid for reach optimization.

languages
string[]

Languages to target as ISO 639 codes (e.g. en, es). Empty/omitted = all languages.

message_apps
enum<string>[]

Required when conversion_location is messaging: which apps to message on. Combinations map to the matching Meta destination.

Available options:
messenger,
instagram,
whatsapp
minimum_daily_spend
number

Daily spend floor within the budget.

optimization_goal
string

What the ad group optimizes for (e.g. conversions, link_clicks, reach).

placements
any

'automatic' (Advantage+) or a list of { platform, positions }. Omit positions to target all of a platform's.

Valid positions per platform:

  • facebook: feed, right_hand_column, marketplace, search, profile_feed, notification, story, instream_video, facebook_reels, facebook_reels_overlay, biz_disco_feed
  • instagram: stream, story, explore, explore_home, reels, profile_feed, profile_reels, ig_search
  • messenger: story
  • audience_network: classic, rewarded_video
  • threads: threads_stream
  • whatsapp: status
regions
object

Geo targeting: { include / exclude: { countries (ISO 3166-1), regions (states/provinces as ISO 3166-2, e.g. US-CA), cities (keyed), zips } }.

starts_at
string

Schedule start, ISO 8601.

status
enum<string>

Initial status (default: active).

Available options:
active,
paused
title
string

The display name of the ad group.

Response

ad group created

ad_campaign
object
required

The ad campaign this ad group belongs to, an object with an id.

added_to_carts
number
required

Whop pixel-attributed add-to-cart events, last-click.

audiences
object
required

Saved-audience targeting: { include, exclude } arrays of audience IDs.

bid_type
enum<string> | null
required

Bid strategy.

Available options:
minimum_cost,
average_target,
maximum_target,
null
Example:

"minimum_cost"

budget_amount
number | null
required

Ad-set budget; null when the campaign owns budget (CBO).

budget_type
enum<string> | null
required

Whether the budget is daily or lifetime.

Available options:
daily,
lifetime,
null
Example:

"daily"

click_through_rate
number
required

Clicks divided by impressions, between 0 and 1.

clicks
number
required

The number of clicks.

completed_registrations
number
required

Whop pixel-attributed complete-registration events, last-click.

contacts
number
required

Whop pixel-attributed contact events, last-click.

conversion_event
required

The pixel event optimized for. A standard event, or any custom pixel event name.

Available options:
purchase,
add_to_cart,
initiated_checkout,
add_payment_info,
complete_registration,
lead,
content_view,
search,
contact,
customize_product,
donate,
find_location,
schedule,
start_trial,
submit_application,
subscribe
conversion_location
enum<string> | null
required

Where results happen: website, profile (IG/FB), messaging (DM), on_ad (engagement), or the lead destinations (instant_forms, instant_forms_and_messenger, website_and_instant_forms).

Available options:
website,
profile,
messaging,
on_ad,
instant_forms,
instant_forms_and_messenger,
website_and_instant_forms,
null
Example:

"website"

cost_per_added_to_cart
number | null
required

Spend divided by attributed add-to-cart events; null when they are not the goal and none are attributed.

cost_per_click
number
required

Spend divided by clicks; 0 when there are no clicks.

cost_per_completed_registration
number | null
required

Spend divided by attributed complete-registration events; null when they are not the goal and none are attributed.

cost_per_contact
number | null
required

Spend divided by attributed contact events; null when contacts are not the goal and none are attributed.

cost_per_lead
number | null
required

Spend divided by attributed leads; null when leads are not a goal and none are attributed.

cost_per_mille
number
required

Spend per 1,000 impressions; 0 when there are no impressions.

cost_per_purchase
number | null
required

Spend divided by attributed purchases; null when purchases are not a goal and none are attributed.

cost_per_result
number | null
required

Spend divided by Whop pixel-attributed results; null when nothing Whop-attributable is being optimized for.

cost_per_schedule
number | null
required

Spend divided by attributed schedule events; null when schedules are not the goal and none are attributed.

cost_per_submitted_application
number | null
required

Spend divided by attributed submit-application events; null when they are not the goal and none are attributed.

cost_per_viewed_content
number | null
required

Spend divided by attributed view-content events; null when they are not the goal and none are attributed.

created_at
string
required

When the ad group was created, ISO 8601.

custom_conversions
number
required

Whop pixel-attributed custom (merchant-defined) conversion events, last-click, across all custom event names.

delivery_status
enum<string>
required

The current delivery state, mirroring the Delivery column in the ads dashboard. When several states apply at once, the highest-precedence one is returned.

Available options:
all_ads_rejected,
rejected,
draft,
no_ads,
campaign_paused,
paused,
processing,
issues,
scheduled,
completed,
ads_off,
learning_limited,
learning,
active
Example:

"all_ads_rejected"

demographics
object
required

Demographic targeting: automatic (Advantage+), age range, gender.

desired_cost_per_result
number | null
required

Target/cap cost for average_target / maximum_target.

devices
object
required

Device targeting: platforms and operating systems.

dynamic_creative
boolean
required

Whether ads within this ad group have their creatives and copy dynamically AB tested.

ends_at
string | null
required

Schedule end, ISO 8601.

frequency
number | null
required

Platform-reported impressions divided by reach.

frequency_cap
object | null
required

Impression cap; only valid for reach optimization.

id
string
required

Unique identifier for the ad group.

impressions
number
required

The number of impressions.

issues
object[]
required
languages
string[]
required

Targeted languages as ISO 639 codes (e.g. en, es). Region-specific Meta locales without an ISO mapping appear as their numeric Meta locale key. Empty = all languages.

leads
number
required

Whop pixel-attributed leads, last-click.

message_apps
string[]
required

For messaging destinations: the apps to message on (messenger, instagram, whatsapp). Empty otherwise.

minimum_daily_spend
number | null
required

Daily spend floor within the budget.

optimization_goal
string | null
required

What the ad group optimizes for.

placements
object[]
required
purchase_value
number
required

USD value of pixel-attributed purchases.

purchases
number
required

Whop pixel-attributed purchases, last-click.

reach
number
required

The number of unique people who saw this.

regions
object
required

Geo targeting: include/exclude countries, regions (ISO 3166-2 states, e.g. US-CA), cities, zips.

result_event
enum<string> | null
required

The Whop pixel conversion event whose attributed count represents results — the optimization goal, or the highest-volume attributed event for campaigns that budget per ad group. Null when the goal isn't a Whop-attributed event.

Available options:
purchase,
lead,
schedule,
submit_application,
contact,
complete_registration,
view_content,
add_to_cart,
custom,
null
Example:

"purchase"

result_event_name
string | null
required

The merchant-defined event name when result_event is custom; null for the standard events.

return_on_ad_spend
number
required

Purchase value divided by spend, both in USD (a currency-neutral ratio); 0 when there is no spend.

schedules
number
required

Whop pixel-attributed schedule events, last-click.

spend
number
required

The amount charged, in spend_currency.

spend_currency
string | null
required

The ISO 4217 currency code of all monetary metrics.

starts_at
string | null
required

Schedule start, ISO 8601.

status
enum<string>
required

Delivery status of the ad group.

Available options:
active,
paused,
rejected
Example:

"active"

submitted_applications
number
required

Whop pixel-attributed submit-application events, last-click.

title
string | null
required

The display title of the ad group.

unique_click_through_rate
number | null
required

Unique clicks divided by impressions, between 0 and 1.

unique_clicks
number
required

The number of unique clicks.

updated_at
string
required

When the ad group was last updated, ISO 8601.

viewed_contents
number
required

Whop pixel-attributed view-content events, last-click.