Hello,
I'm successfully creating campaigns, ad groups, and ads using the Google Ads API v18, and even setting conversion goals works as expected. However, I’m encountering an issue with the ad schedule configuration. Although my API call for applying ad schedule criteria appears to succeed (i.e. no errors and valid logging messages), the campaign in the Google Ads dashboard shows no ad schedule—it's as if the default (or no) ad schedule is applied.
Below is my PHP code snippet for applying the ad schedule:
private function applyAdSchedule($googleAdsClient, $customerId, $campaignResourceName, $requestData)
{
if (empty($requestData['campaign']['ad_schedule'])) {
Log::warning("⚠️ No ad schedule provided.");
return;
}
$operations = [];
foreach ($requestData['campaign']['ad_schedule'] as $schedule) {
try {
Log::info("🟢 Processing Ad Schedule: " . json_encode($schedule));
// Convert ENUM values properly
$dayOfWeek = strtoupper($schedule['day_of_week']);
$startMinute = strtoupper($schedule['start_minute']);
$endMinute = strtoupper($schedule['end_minute']);
// Validate ENUM definitions
if (!defined("\Google\Ads\GoogleAds\V18\Enums\DayOfWeekEnum\DayOfWeek::$dayOfWeek")) {
Log::error("🚨 Invalid day_of_week ENUM: " . $dayOfWeek);
continue;
}
if (
!defined("\Google\Ads\GoogleAds\V18\Enums\MinuteOfHourEnum\MinuteOfHour::$startMinute") ||
!defined("\Google\Ads\GoogleAds\V18\Enums\MinuteOfHourEnum\MinuteOfHour::$endMinute")
) {
Log::error("🚨 Invalid start_minute or end_minute ENUM.");
continue;
}
$dayEnum = DayOfWeek::value(strtoupper($schedule['day_of_week']));
$startMinuteEnum = MinuteOfHour::value(strtoupper($schedule['start_minute']));
$endMinuteEnum = MinuteOfHour::value(strtoupper($schedule['end_minute']));
// Validate Start and End Time
if (
$schedule['start_hour'] > $schedule['end_hour'] ||
($schedule['start_hour'] == $schedule['end_hour'] && $schedule['start_minute'] >= $schedule['end_minute'])
) {
Log::error("🚨 Invalid Ad Schedule: End time cannot be before or equal to start time.");
continue;
}
// Create the Ad Schedule operation
$operations[] = new CampaignCriterionOperation([
'create' => new CampaignCriterion([
'campaign' => $campaignResourceName,
'ad_schedule' => new AdScheduleInfo([
'day_of_week' => $dayEnum,
'start_hour' => (int) $schedule['start_hour'],
'start_minute' => $startMinuteEnum,
'end_hour' => (int) $schedule['end_hour'],
'end_minute' => $endMinuteEnum,
])
])
]);
} catch (\Throwable $th) {
Log::error("🔴 Error Creating Ad Schedule: " . $th->getMessage());
}
}
if (empty($operations)) {
Log::error("❌ No valid Ad Schedule operations created.");
return;
} else {
Log::info("✅ Valid Ad Schedule Operations: ", ['operations' => json_encode($operations)]);
}
try {
Log::info("📢 Sending Ad Schedule to Google Ads API: " . json_encode($operations));
$response = $googleAdsClient->getCampaignCriterionServiceClient()->mutateCampaignCriteria(new MutateCampaignCriteriaRequest([
'customer_id' => $customerId,
'operations' => $operations
]));
Log::info("✅ Ad Schedule Applied Successfully: " . json_encode($response->getResults()));
} catch (\Throwable $th) {
Log::error("🚨 Google Ads API Error in Ad Schedule: " . $th->getMessage());
}
}
And here’s an example of the JSON payload I’m passing:
{
"campaignBudget": 10000000,
"campaign": {
"name": "Test Campaign",
"status": "PAUSED",
"type": "SEARCH",
"start_date": "2025-02-25",
"end_date": "",
"locations": [
{
"id": 2028,
"name": "Antigua and Barbuda"
}
],
"languages": [
{
"id": 1000,
"name": "English"
}
],
"networks": [
"SEARCH",
"DISPLAY"
],
"ad_schedule": [
{
"day_of_week": "MONDAY",
"start_hour": 0,
"start_minute": "ZERO",
"end_hour": 12,
"end_minute": "ZERO"
}
],
"conversion_goals": [
{
"category": "ENGAGEMENT",
"origin": "YOUTUBE_HOSTED",
"biddable": true
}
]
},
"adGroup": {
"name": "Test Ad Group",
"cpc_bid_micros": 1000000,
"keywords": [
"adgpt"
]
},
"ad": {
"businessName": "",
"headlines": [
"AdGPT - Your AI Ads Manager",
"AdGPT - Your AI Ads Manager",
"AdGPT - Your AI Ads Manager"
],
"descriptions": [
"Boost sales with AdGPT.com for Nike Shoes ads",
"Boost sales with AdGPT.com for Nike Shoes ads",
"Boost sales with AdGPT.com for Nike Shoes ads"
],
"final_urls": [
"adgpt.com"
]
},
"brand_id": 192
}
My Questions:
Why is the ad schedule not being applied?
Although the log indicates valid operations and the mutate request returns success, the campaign still shows no ad schedule. Is there a known nuance with the ad schedule mutation in API v18?
Are there specific campaign settings or additional steps required for ad schedules to take effect?
For example, does the campaign need to be in a particular status or have certain criteria set before the ad schedule is recognized?
Could there be issues with the ENUM conversion for day or minute values?
I’m validating against DayOfWeek and MinuteOfHour enums, and the payload uses "MONDAY" for day and "ZERO" for minutes. Are these the correct values per the API documentation?
Any insights, debugging tips, or recommended changes would be greatly appreciated. Thanks in advance for your help!
1. Why is the ad schedule not being applied?
Although the log indicates valid operations and the mutate request returns success, the campaign still shows no ad schedule. Is there a known nuance with the ad schedule mutation in API v18?
2. Are there specific campaign settings or additional steps required for ad schedules to take effect?
For example, does the campaign need to be in a particular status or have certain criteria set before the ad schedule is recognized?
3. Could there be issues with the ENUM conversion for day or minute values?
I’m validating against DayOfWeek and MinuteOfHour enums, and the payload uses "MONDAY" for day and "ZERO" for minutes. Are these the correct values per the API documentation?
![]() |
Google Ads API Team |
[2025-02-25 16:04:41Z GMT] This message is in relation to case "ref:!00D1U01174p.!5004Q02vH3ow:ref" (ADR-00289730)