Campaign Management Behavior & Nuances
Documentation Disclaimer
This documentation is not exhaustive and does not guarantee system behavior. Integrators are responsible for testing against actual API responses. See Documentation Disclaimer for full details.
Campaign Management Behavior & Nuances
The Yelp Ads API is straightforward for basic create/modify/terminate operations, but several behaviors are non-obvious and can cause integration issues if not understood upfront. This page documents confirmed gotchas that go beyond the API spec.
Table of Contents
- Program Creation & Feature Carryover
- Strict Category Targeting (SCT)
- Budget Changes, Pausing & Termination
- Async Job Processing
- Promo Campaigns
- Program Lifecycle & Ad Content
- Geotargeting & Custom Location Targeting
- UTM Tracking & Link Tracking
- API vs. Yelp UI
Program Creation & Feature Carryover
POST /v1/reseller/program/create always creates a new program — it never updates an existing one.
There is no upsert behavior. Each call to the create endpoint results in a brand-new program, regardless of whether an active program already exists for that business.
Features must be set explicitly after creation.
Features such as Strict Category Targeting (SCT), ad scheduling, and radius targeting are configured via a separate endpoint (POST /program/{program_id}/features/v1). They are never set implicitly or inherited — they must be applied explicitly after each program creation.
Budget changes that create a new program reset all features.
When a budget modification results in a new program being created on the backend, that new program starts with no active features. SCT and all other features must be re-applied explicitly on the new program ID via the features endpoint.
promotion_code can only be attached at creation time.
A promo code cannot be added retroactively via /edit. It must be included in the original POST /create call.
program_name determines program type — editing it does not convert types.
Sending a different program_name on an edit call does not change the program type (e.g., CPC to BP). To change program types, use a terminate + create flow.
Multiple CPC programs can run simultaneously for the same business.
A business can have multiple CPC programs running at the same time with overlapping budget cycles.
fee_period cannot be changed once a program has started.
The billing cycle (CALENDAR_MONTH or ROLLING_MONTH) is locked at creation time and cannot be modified on a running program.
Strict Category Targeting (SCT)
SCT only enforces targeting in search and business-details ad recall.
RaX (Retargeting) and RAQ ad placements ignore SCT entirely and always apply loose category expansion, regardless of the SCT setting. This is a known platform limitation.
Without SCT, campaigns expand into adjacent and implied categories by design.
For example, a "catering" campaign can serve on "weddings" or "parties" pages. This is expected behavior, not a bug.
SCT is configured per campaign, not per business.
There is no business-level SCT setting. Each program must have SCT configured independently.
SCT does not carry over when a budget change creates a new program.
Because the new program starts with no features, SCT must be explicitly re-enabled on the new program ID after any budget-change-triggered program recreation.
Budget Changes, Pausing & Termination
Pausing and cancelling are not equivalent.
Some promotions are dropped when a program is paused. Additionally, free trial programs cannot be paused at all — attempting to pause one will fail.
Retroactive end-time changes can produce unattributable costs.
Changing a program's end date to a time in the past can leave clicks or impressions that occurred during the gap without an associated active campaign. This can result in spend that does not map to a running program.
Budget edits while a business is delinquent can trigger unexpected side effects.
Editing budget on a program while the associated business account is in a delinquent state may have unintended effects on other active programs for that business. Confirm account standing before submitting budget modifications.
Unused budget does not roll over.
Monthly budgets reset and unspent amounts are not carried into the next cycle.
Yelp will not charge over the target budget.
Yelp may over-deliver impressions, but the budget is the maximum charged for that period — over-delivered impressions are not billed.
Budget can be changed immediately or scheduled for a future date.
Use future_budget_date to schedule a budget change; omitting it applies the change immediately. Budget can be updated at any time within a 30-day cycle.
Terminated campaigns that never started are not queryable.
If a campaign is terminated before its start date, the program_id is invalidated. It will not appear in partner support API responses and cannot be used as input to other requests. Campaigns that actually started remain queryable after termination.
Async Job Processing
A 200 response on create or modify only means the job was queued — not that it succeeded.
The API is asynchronous. The initial response returns a job_id; the actual validation and processing happen in a background worker.
Jobs can be accepted and then later REJECTED.
Validation does not happen at submission time. A job may return 200 and then later resolve to REJECTED status when polled. Always treat the initial response as a receipt, not a confirmation.
Always poll GET /v1/reseller/status/{job_id} until a terminal state.
Poll until the status is COMPLETED or REJECTED. Never infer success from the initial 200 response alone.
PARENT_WAS_REJECTED errors indicate cascading failures.
If you see PARENT_WAS_REJECTED on a child field, it means a parent-level validation failed first. Find the single top-level validation error in the response — that is the root cause.
Budget is in cents, not dollars.
The minimum budget is 2500, which equals $25.00. Sending 25 means $0.25 and will be rejected. This is a common misconfiguration.
Concurrent overlapping submissions can cause last-writer-wins conflicts.
Store the job_id for each submission and wait for a terminal state before submitting another update to the same program. Overlapping in-flight jobs targeting the same program can result in unpredictable outcomes where the last job to complete overwrites earlier ones.
Promo Campaigns
Promo codes can only be applied to new advertisers.
Only businesses that have not advertised with Yelp in the past 6 months are eligible.
Promo code must be set at creation time — it cannot be changed later.
Once a campaign is created with a promo code, the code is locked. To use a different code, fail and retry with a corrected POST /create call.
If the promo code is invalid, the primary campaign is also rejected.
The primary and promo campaigns are evaluated together. An invalid promo code causes both to fail.
The promo campaign has the same start date as the primary, with an end date 6 months later (last day of the month).
Use this pattern to identify promo campaigns in the program list: same start date as the primary campaign, and end_month = start_month + 6.
Promo campaigns are terminated nightly if the qualifying primary campaign loses eligibility.
If the primary campaign's budget drops below the promo threshold, the promo campaign is terminated by an automated job. There is no explicit error — the promo program moves to INACTIVE and its end_date is updated to the termination date.
Increasing budget on a primary campaign does not generate a higher promo budget.
Promo budgets are fixed at creation. Reducing budget below threshold terminates the promo; increasing it does not create a new one.
Promo campaigns are reported on separately with a unique program_id.
Promo spend and metrics are not aggregated with the primary campaign in reporting.
Promo campaigns are automatically ended when the primary campaign is terminated.
This is handled via a nightly job — the promo's end_date is updated to match the primary's termination date.
Program Lifecycle & Ad Content
Ad text is sourced from reviews or the "about the business specialties" field.
CPC ads use review text by default. If there are insufficient reviews, Yelp falls back to the specialties field. If neither exists, the ad is accepted and runs only as a mobile search ad. Custom ad text is not supported via the API.
Enhanced profiles and CPC programs are independent.
They are created and managed as two distinct programs via the API — not formally bundled. However, Enhanced Profiles include features (no competitor ads, photo sequencing, call to action) that apply to all traffic, organic and paid.
Enhanced Profiles are not prorated.
Once purchased, a profile runs until explicitly ended. There is no prorated billing for profile products.
CTAs are automatically removed when the profile product ends.
A nightly job removes CTAs when the associated Enhanced Profile program is ended.
There is no API field for custom campaign names.
The program_id is the unique identifier for a campaign on Yelp. There is no name field that Yelp stores or exposes.
Geotargeting & Custom Location Targeting
Custom Location Targeting (CLT) replaces default targeting — it does not add to it.
Anything set via CLT overrides the default geotargeting (service area or physical location radius). CLT and custom radius targeting cannot both be active simultaneously — setting one will remove the other.
Yelp normalizes location inputs — log the response to confirm actual targeting.
Some city and county names are ambiguous. Yelp normalizes inputs, so the resulting targeting may differ slightly from what was submitted. Always log the response to verify.
Postal codes are the most reliable CLT input.
City and neighborhood names can be ambiguous. Postal codes map to a finite, unambiguous set of values and are less prone to normalization issues.
CLT is limited to 25 locations within the US.
Supported location types: zip codes, cities, neighborhoods, counties, and state names.
Custom radius targeting is available via CUSTOM_RADIUS_TARGETING in the program features API.
A program can revert to standard radius targeting by removing the custom location target — but CLT and custom radius cannot coexist.
UTM Tracking & Link Tracking
Link tracking via the program features API applies only to CPC ad traffic — not organic.
Setting LINK_TRACKING appends query parameters only to traffic attributed to the CPC program. Organic traffic uses the URL set in the data ingestion API.
Tracking parameters can be applied to website URL, menu URL, or CTA.
Use LINK_TRACKING in the program feature API to append tracking parameters (e.g., {"LINK_TRACKING": {"website": "source=yelpweb"}} appends ?source=yelpweb).
AD_GOAL: WEBSITE_CLICKS sends consumers directly to the external website from the ad.
Setting this ad goal surfaces a CTA in search results that bypasses the Yelp profile page and goes directly to the merchant website.
API vs. Yelp UI
Programs created via API are not automatically visible in biz.yelp.com.
Yelp must explicitly grant access for each business owner account to the partner account. Without this, campaigns purchased via API will not appear in the Yelp for Business UI.
Only manage campaigns via one channel.
Managing campaigns through both the API and the biz.yelp.com UI simultaneously is not recommended and can lead to inconsistent state.
Credentials are scoped to a payment account — you can only see programs you created.
Partner API credentials are tied to your payment account. You cannot view or manage programs created by other providers for the same business.
Updated 2 days ago
