import { WhopClient } from "@whop/sdk";
const client = new WhopClient({ token: "YOUR_TOKEN", apiVersionDate: "2026-08-21-1", idempotencyKey: "YOUR_IDEMPOTENCY_KEY" });
await client.adGroups.list({
ad_campaign_ids: ["adcamp_xxxxxxxxxxxxxx"]
});curl --request GET \
--url https://api.whop.com/api/v1/ad_groups \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.whop.com/api/v1/ad_groups"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
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 => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.whop.com/api/v1/ad_groups"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.whop.com/api/v1/ad_groups")
.header("Authorization", "Bearer <token>")
.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::Get.new(url)
request["Authorization"] = 'Bearer <token>'
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": [
{
"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"
}
],
"languages": [
"en"
],
"lead_value": 3960,
"leads": 132,
"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,
"message_apps": [
"instagram"
],
"minimum_daily_spend": 25
}
],
"page_info": {
"end_cursor": null,
"has_next_page": false,
"has_previous_page": false,
"start_cursor": "WyJjdXJzb3IiLDFd"
}
}List Ad Groups
Lists ad groups for the account, newest first.
import { WhopClient } from "@whop/sdk";
const client = new WhopClient({ token: "YOUR_TOKEN", apiVersionDate: "2026-08-21-1", idempotencyKey: "YOUR_IDEMPOTENCY_KEY" });
await client.adGroups.list({
ad_campaign_ids: ["adcamp_xxxxxxxxxxxxxx"]
});curl --request GET \
--url https://api.whop.com/api/v1/ad_groups \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.whop.com/api/v1/ad_groups"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
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 => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.whop.com/api/v1/ad_groups"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.whop.com/api/v1/ad_groups")
.header("Authorization", "Bearer <token>")
.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::Get.new(url)
request["Authorization"] = 'Bearer <token>'
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": [
{
"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"
}
],
"languages": [
"en"
],
"lead_value": 3960,
"leads": 132,
"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,
"message_apps": [
"instagram"
],
"minimum_daily_spend": 25
}
],
"page_info": {
"end_cursor": null,
"has_next_page": false,
"has_previous_page": false,
"start_cursor": "WyJjdXJzb3IiLDFd"
}
}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
Pins the request to a dated API version.
"2026-09-29"
Query Parameters
Account whose ad groups to list. Defaults to the authenticated account.
Filter to ad groups in this campaign.
Filter to ad groups in these campaigns (max 100). Repeat the parameter for each id (ad_campaign_ids=a&ad_campaign_ids=b).
Filter to ad groups with this status.
active, paused, rejected, duplicating Filter ad groups by a title or ID substring.
The field to sort by. Defaults to created_at. Stat columns (spend, impressions, …) rank over the stats_from/stats_to window across the whole list, not just the current page. results, cost_per_result and return_on_ad_spend rank by the same Whop pixel-attributed values the response reports.
created_at, updated_at, spend, impressions, reach, clicks, link_clicks, unique_clicks, frequency, click_through_rate, results, cost_per_mille, cost_per_click, cost_per_result, return_on_ad_spend The sort direction. Defaults to desc.
asc, desc Only return ad groups created before this timestamp.
Only return ad groups created after this timestamp.
Start of the stats window. Defaults to all-time.
End of the stats window. Defaults to now.
IANA timezone (e.g. America/New_York) the stats window is interpreted in. Bare stats_from/stats_to dates resolve to day boundaries on this clock. Defaults to UTC.
Attribution model the conversion stats count under (defaults to last_touch). Under both models a journey with any whop ad touch attributes to whop; the model picks which whop touch credits the entity and which non-whop source wins otherwise.
last_touch, first_touch Number of results to return from the start of the range.
x <= 100Return results after this cursor. Use page_info.end_cursor from the previous response to fetch the next page.
Number of results to return from the end of the range.
x <= 100Return results before this cursor. Use page_info.start_cursor from the previous response to fetch the previous page.

