import { WhopClient } from "@whop/sdk";
const client = new WhopClient({ token: "YOUR_TOKEN", apiVersionDate: "2026-08-21-1", idempotencyKey: "YOUR_IDEMPOTENCY_KEY" });
await client.adGroups.duplicate({
id: "id"
});curl --request POST \
--url https://api.whop.com/api/v1/ad_groups/{id}/duplicate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"count": 2,
"preserve_engagement": true,
"target_ad_campaign_id": "adcamp_xxxxxxxxxxxxxx"
}
'import requests
url = "https://api.whop.com/api/v1/ad_groups/{id}/duplicate"
payload = {
"count": 2,
"preserve_engagement": True,
"target_ad_campaign_id": "adcamp_xxxxxxxxxxxxxx"
}
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({
count: 2,
preserve_engagement: true,
target_ad_campaign_id: 'adcamp_xxxxxxxxxxxxxx'
})
};
fetch('https://api.whop.com/api/v1/ad_groups/{id}/duplicate', 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/{id}/duplicate",
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([
'count' => 2,
'preserve_engagement' => true,
'target_ad_campaign_id' => 'adcamp_xxxxxxxxxxxxxx'
]),
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/{id}/duplicate"
payload := strings.NewReader("{\n \"count\": 2,\n \"preserve_engagement\": true,\n \"target_ad_campaign_id\": \"adcamp_xxxxxxxxxxxxxx\"\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/{id}/duplicate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"count\": 2,\n \"preserve_engagement\": true,\n \"target_ad_campaign_id\": \"adcamp_xxxxxxxxxxxxxx\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.whop.com/api/v1/ad_groups/{id}/duplicate")
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 \"count\": 2,\n \"preserve_engagement\": true,\n \"target_ad_campaign_id\": \"adcamp_xxxxxxxxxxxxxx\"\n}"
response = http.request(request)
puts response.read_body{
"data": [
{
"ad_campaign": {
"id": "adcamp_xxxxxxxxxxxxxx"
},
"added_to_cart_value": 12650,
"added_to_carts": 165,
"audiences": {
"exclude": [
"adaud_xxxxxxxxxxxxxx"
],
"include": [
"adaud_xxxxxxxxxxxxxx"
]
},
"bid_type": "average_target",
"budget_amount": 60,
"budget_amount_local": 60,
"budget_currency": "usd",
"budget_type": "daily",
"click_through_rate": 0.025,
"clicks": 5500,
"completed_registration_value": 1650,
"completed_registrations": 55,
"contact_value": 2640,
"contacts": 88,
"conversion_event": "purchase",
"cost_per_added_to_cart": 8,
"cost_per_click": 0.24,
"cost_per_completed_registration": 24,
"cost_per_contact": 15,
"cost_per_lead": 10,
"cost_per_mille": 6,
"cost_per_purchase": 30,
"cost_per_result": 40,
"cost_per_schedule": 22,
"cost_per_submitted_application": 120,
"cost_per_unique_click": 0.4,
"cost_per_viewed_content": 1.1,
"created_at": "2026-01-01T12:00:00.000Z",
"custom_conversions": 41,
"custom_event_counts": {
"gift_card_purchased": 5,
"quote_requested": 33
},
"custom_event_values": {
"gift_card_purchased": 750,
"quote_requested": 0
},
"delivery_schedule": {
"friday": [
{
"end": "12:00",
"start": "10:00"
}
],
"monday": [
{
"end": "12:00",
"start": "10:00"
}
],
"saturday": [
{
"end": "12:00",
"start": "10:00"
}
],
"sunday": [
{
"end": "12:00",
"start": "10:00"
}
],
"thursday": [
{
"end": "12:00",
"start": "10:00"
}
],
"tuesday": [
{
"end": "12:00",
"start": "10:00"
}
],
"wednesday": [
{
"end": "12:00",
"start": "10:00"
}
]
},
"delivery_status": "no_ads",
"demographics": {
"automatic": false,
"gender": "all",
"maximum_age": 64,
"minimum_age": 21
},
"desired_cost_per_result": 40,
"detailed_targeting": {
"behaviors": [
{
"id": "6007101291578",
"behavior_type": "video",
"name": "Recent vehicle purchase (30 days)",
"period": 123
}
],
"demographics": [
{
"id": "6002714398172",
"type": "life_events",
"name": "Recently moved"
}
],
"interests": [
{
"id": "6003193685204",
"name": "Car wash"
}
]
},
"devices": {
"operating_systems": [
{
"os": "ios",
"minimum_version": "18.0"
}
],
"platforms": [
"mobile"
]
},
"ends_at": "2026-01-01T12:00:00.000Z",
"frequency": null,
"frequency_cap": {
"maximum_impressions": 3,
"per_days": 7
},
"id": "adgrp_xxxxxxxxxxxxxx",
"impressions": 220000,
"issues": [
{
"category": "error",
"id": "adiss_xxxxxxxxxxxxxx",
"message": "Your ad was rejected for unacceptable business practices. Edit the ad's content and resubmit.",
"resource_id": "ad_xxxxxxxxxxxxxx",
"resource_type": "ad",
"title": "Ad issue"
}
],
"languages": [
"en"
],
"lead_value": 3960,
"leads": 132,
"learning_progress": {
"conversion_threshold": 123,
"conversions": 123,
"progress_percent": 123
},
"link_clicks": 4400,
"optimization_goal": "conversions",
"placements": [
{
"platform": "facebook",
"positions": [
"feed"
]
}
],
"platform": "meta",
"purchase_value": 7920,
"purchases": 44,
"reach": 0,
"regions": {
"exclude": {
"cities": [
{
"key": "2418046",
"name": "Austin"
}
],
"countries": [
"US"
],
"country_groups": [
"north_america"
],
"custom_locations": [
{
"distance_unit": "mile",
"latitude": 30.2672,
"longitude": -97.7431,
"radius": 25,
"country_code": "<string>",
"name": "4180 Burnet Rd, Austin TX 78756"
}
],
"regions": [
"US-TX"
],
"zips": [
"US:78756"
]
},
"include": {
"cities": [
{
"key": "2418046",
"name": "Austin"
}
],
"countries": [
"US"
],
"country_groups": [
"north_america"
],
"custom_locations": [
{
"distance_unit": "mile",
"latitude": 30.2672,
"longitude": -97.7431,
"radius": 25,
"country_code": "<string>",
"name": "4180 Burnet Rd, Austin TX 78756"
}
],
"regions": [
"US-TX"
],
"zips": [
"US:78756"
]
}
},
"result_event": "custom",
"result_event_name": "quote_requested",
"results": 33,
"return_on_ad_spend": 6,
"schedule_value": 5400,
"schedules": 60,
"spend": 1320,
"spend_currency": "usd",
"starts_at": "2026-01-01T12:00:00.000Z",
"status": "active",
"submitted_application_value": 1320,
"submitted_applications": 11,
"title": "Austin ceramic coating — repeat customers",
"unique_click_through_rate": null,
"unique_clicks": 3300,
"updated_at": "2026-01-01T12:00:00.000Z",
"viewed_content_value": 8400,
"viewed_contents": 1200,
"conversion_location": "website",
"dynamic_creative": false,
"keywords": [
{
"match_type": "broad",
"negative": true,
"text": "<string>"
}
],
"message_apps": [
"instagram"
],
"minimum_daily_spend": 25
}
]
}{
"error": {
"message": "account_id is required",
"type": "bad_request",
"code": "<string>"
}
}{
"error": {
"message": "account_id is required",
"type": "bad_request",
"code": "<string>"
}
}{
"error": {
"message": "account_id is required",
"type": "bad_request",
"code": "<string>"
}
}Duplicate an Ad Group
Starts copying an ad group and returns the copies in duplicating status. Poll each returned ad group until it leaves duplicating: it then takes the source’s active or paused status, or, if the copy could not be completed, is deleted and returns 404.
import { WhopClient } from "@whop/sdk";
const client = new WhopClient({ token: "YOUR_TOKEN", apiVersionDate: "2026-08-21-1", idempotencyKey: "YOUR_IDEMPOTENCY_KEY" });
await client.adGroups.duplicate({
id: "id"
});curl --request POST \
--url https://api.whop.com/api/v1/ad_groups/{id}/duplicate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"count": 2,
"preserve_engagement": true,
"target_ad_campaign_id": "adcamp_xxxxxxxxxxxxxx"
}
'import requests
url = "https://api.whop.com/api/v1/ad_groups/{id}/duplicate"
payload = {
"count": 2,
"preserve_engagement": True,
"target_ad_campaign_id": "adcamp_xxxxxxxxxxxxxx"
}
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({
count: 2,
preserve_engagement: true,
target_ad_campaign_id: 'adcamp_xxxxxxxxxxxxxx'
})
};
fetch('https://api.whop.com/api/v1/ad_groups/{id}/duplicate', 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/{id}/duplicate",
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([
'count' => 2,
'preserve_engagement' => true,
'target_ad_campaign_id' => 'adcamp_xxxxxxxxxxxxxx'
]),
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/{id}/duplicate"
payload := strings.NewReader("{\n \"count\": 2,\n \"preserve_engagement\": true,\n \"target_ad_campaign_id\": \"adcamp_xxxxxxxxxxxxxx\"\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/{id}/duplicate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"count\": 2,\n \"preserve_engagement\": true,\n \"target_ad_campaign_id\": \"adcamp_xxxxxxxxxxxxxx\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.whop.com/api/v1/ad_groups/{id}/duplicate")
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 \"count\": 2,\n \"preserve_engagement\": true,\n \"target_ad_campaign_id\": \"adcamp_xxxxxxxxxxxxxx\"\n}"
response = http.request(request)
puts response.read_body{
"data": [
{
"ad_campaign": {
"id": "adcamp_xxxxxxxxxxxxxx"
},
"added_to_cart_value": 12650,
"added_to_carts": 165,
"audiences": {
"exclude": [
"adaud_xxxxxxxxxxxxxx"
],
"include": [
"adaud_xxxxxxxxxxxxxx"
]
},
"bid_type": "average_target",
"budget_amount": 60,
"budget_amount_local": 60,
"budget_currency": "usd",
"budget_type": "daily",
"click_through_rate": 0.025,
"clicks": 5500,
"completed_registration_value": 1650,
"completed_registrations": 55,
"contact_value": 2640,
"contacts": 88,
"conversion_event": "purchase",
"cost_per_added_to_cart": 8,
"cost_per_click": 0.24,
"cost_per_completed_registration": 24,
"cost_per_contact": 15,
"cost_per_lead": 10,
"cost_per_mille": 6,
"cost_per_purchase": 30,
"cost_per_result": 40,
"cost_per_schedule": 22,
"cost_per_submitted_application": 120,
"cost_per_unique_click": 0.4,
"cost_per_viewed_content": 1.1,
"created_at": "2026-01-01T12:00:00.000Z",
"custom_conversions": 41,
"custom_event_counts": {
"gift_card_purchased": 5,
"quote_requested": 33
},
"custom_event_values": {
"gift_card_purchased": 750,
"quote_requested": 0
},
"delivery_schedule": {
"friday": [
{
"end": "12:00",
"start": "10:00"
}
],
"monday": [
{
"end": "12:00",
"start": "10:00"
}
],
"saturday": [
{
"end": "12:00",
"start": "10:00"
}
],
"sunday": [
{
"end": "12:00",
"start": "10:00"
}
],
"thursday": [
{
"end": "12:00",
"start": "10:00"
}
],
"tuesday": [
{
"end": "12:00",
"start": "10:00"
}
],
"wednesday": [
{
"end": "12:00",
"start": "10:00"
}
]
},
"delivery_status": "no_ads",
"demographics": {
"automatic": false,
"gender": "all",
"maximum_age": 64,
"minimum_age": 21
},
"desired_cost_per_result": 40,
"detailed_targeting": {
"behaviors": [
{
"id": "6007101291578",
"behavior_type": "video",
"name": "Recent vehicle purchase (30 days)",
"period": 123
}
],
"demographics": [
{
"id": "6002714398172",
"type": "life_events",
"name": "Recently moved"
}
],
"interests": [
{
"id": "6003193685204",
"name": "Car wash"
}
]
},
"devices": {
"operating_systems": [
{
"os": "ios",
"minimum_version": "18.0"
}
],
"platforms": [
"mobile"
]
},
"ends_at": "2026-01-01T12:00:00.000Z",
"frequency": null,
"frequency_cap": {
"maximum_impressions": 3,
"per_days": 7
},
"id": "adgrp_xxxxxxxxxxxxxx",
"impressions": 220000,
"issues": [
{
"category": "error",
"id": "adiss_xxxxxxxxxxxxxx",
"message": "Your ad was rejected for unacceptable business practices. Edit the ad's content and resubmit.",
"resource_id": "ad_xxxxxxxxxxxxxx",
"resource_type": "ad",
"title": "Ad issue"
}
],
"languages": [
"en"
],
"lead_value": 3960,
"leads": 132,
"learning_progress": {
"conversion_threshold": 123,
"conversions": 123,
"progress_percent": 123
},
"link_clicks": 4400,
"optimization_goal": "conversions",
"placements": [
{
"platform": "facebook",
"positions": [
"feed"
]
}
],
"platform": "meta",
"purchase_value": 7920,
"purchases": 44,
"reach": 0,
"regions": {
"exclude": {
"cities": [
{
"key": "2418046",
"name": "Austin"
}
],
"countries": [
"US"
],
"country_groups": [
"north_america"
],
"custom_locations": [
{
"distance_unit": "mile",
"latitude": 30.2672,
"longitude": -97.7431,
"radius": 25,
"country_code": "<string>",
"name": "4180 Burnet Rd, Austin TX 78756"
}
],
"regions": [
"US-TX"
],
"zips": [
"US:78756"
]
},
"include": {
"cities": [
{
"key": "2418046",
"name": "Austin"
}
],
"countries": [
"US"
],
"country_groups": [
"north_america"
],
"custom_locations": [
{
"distance_unit": "mile",
"latitude": 30.2672,
"longitude": -97.7431,
"radius": 25,
"country_code": "<string>",
"name": "4180 Burnet Rd, Austin TX 78756"
}
],
"regions": [
"US-TX"
],
"zips": [
"US:78756"
]
}
},
"result_event": "custom",
"result_event_name": "quote_requested",
"results": 33,
"return_on_ad_spend": 6,
"schedule_value": 5400,
"schedules": 60,
"spend": 1320,
"spend_currency": "usd",
"starts_at": "2026-01-01T12:00:00.000Z",
"status": "active",
"submitted_application_value": 1320,
"submitted_applications": 11,
"title": "Austin ceramic coating — repeat customers",
"unique_click_through_rate": null,
"unique_clicks": 3300,
"updated_at": "2026-01-01T12:00:00.000Z",
"viewed_content_value": 8400,
"viewed_contents": 1200,
"conversion_location": "website",
"dynamic_creative": false,
"keywords": [
{
"match_type": "broad",
"negative": true,
"text": "<string>"
}
],
"message_apps": [
"instagram"
],
"minimum_daily_spend": 25
}
]
}{
"error": {
"message": "account_id is required",
"type": "bad_request",
"code": "<string>"
}
}{
"error": {
"message": "account_id is required",
"type": "bad_request",
"code": "<string>"
}
}{
"error": {
"message": "account_id is required",
"type": "bad_request",
"code": "<string>"
}
}Authorizations
An Account API key, an App API key, an account access token, an account-scoped user token, or a user OAuth token. Prepend the key or token with Bearer, for example Bearer ***************************. See Auth & API keys for how to get each one.
Headers
A unique key that makes this request safe to retry. See Idempotent requests.
255"d9105228-4a08-46b1-8b91-42fed586d383"
Pins the request to a dated API version.
"2026-10-09-2"
Path Parameters
The ad group ID.
Body
Number of copies to create (1-10). Defaults to 1.
2
Whether the copied ads keep the original posts' engagement (likes, comments, shares). Defaults to false.
true
Campaign to duplicate into. Must belong to the same account and be compatible with the ad group's targeting and goals. Defaults to the ad group's own campaign.
"adcamp_xxxxxxxxxxxxxx"
Response
ad group duplication started
Show child attributes
Show child attributes

