This page is also available in Ukrainian.
Overview
This release adds two major groups of endpoints:- Google Ads Management CRUD — create, update, and delete ad groups, ads (RSAs), keywords, ad schedule, and location targeting directly via the API
- Live Campaign Editing — read and update settings on already-published Google Ads campaigns
Changes to existing endpoints
login_customer_id parameter no longer needed
The login_customer_id query parameter is no longer used by any Google Ads
endpoint. The backend now resolves it automatically from the database based on
customer_id.
If you’re currently passing login_customer_id, nothing will break — it’s
simply ignored. However, we recommend removing it from your API calls to keep
things clean, since it no longer has any effect.
New campaign_id filter on /ads endpoint
The GET /ads endpoint now accepts an optional campaign_id query parameter to
filter ads by campaign. This is in addition to the existing ad_group_id filter.
Status filters relaxed
Data table endpoints that previously returned onlyENABLED resources now also
return PAUSED resources. This affects campaigns, ad groups, ads, and keywords.
The frontend should be prepared to display both statuses.
Server-side search (?search=)
All data table GET endpoints now support a search query parameter. See the
dedicated Table Search guide for the full API spec
(searchable fields per table, parameter rules, etc.).
This section focuses on how to implement search on the frontend, based on
how admin.cattix.com already does it.
Two levels of search
The admin panel implements search at two levels:- Per-table search bar — a text input above each data table that filters
that specific table via
?search=<term> - Global search dialog (
Cmd+K) — fires the same?search=query against all 7 tables in parallel, showing results grouped by category
Recommended implementation pattern
1. Debounce the input (300ms)
Don’t fire an API call on every keystroke. The admin uses a 300ms debounce:2. Prevent stale results (race condition guard)
If the user types “sho” then quickly changes to “brand”, the “sho” response may arrive after “brand”. Use a search-ID ref to discard stale responses:3. For global search — fire parallel requests
The admin fires all 7 category requests independently (not withPromise.all),
so results appear progressively as each category resolves:
4. UI states to handle
| State | What to show |
|---|---|
| No customer selected | Disabled input, prompt to select account |
| Empty query | Placeholder text (e.g. “Search campaigns, ads, keywords…”) |
| Loading | Skeleton rows or spinner per category |
| Partial results | Show resolved categories, skeleton for pending ones |
| No results | ”No results for ‘query‘“ |
| Error | Per-category error message |
5. Navigate from global search to table
When a user selects a result in the global dialog, navigate to the data table with the search pre-filled:search from URL params and auto-fetch on mount.
Reference implementation
The full working implementation lives inadmin.cattix.com:
| File | Purpose |
|---|---|
src/hooks/use-global-search.ts | Search hook with debounce, parallel requests, race-condition guard |
src/components/global-search-dialog.tsx | Cmd+K dialog UI with cmdk |
src/lib/api/google-ads.ts | API client that passes search param |
src/app/admin/google-ads-data/page.tsx | Data page that reads ?search= from URL |
Google Ads Management CRUD
All management endpoints are under the/api/v1/google-ads/ prefix and require
a customer_id query parameter.
Base URL pattern:
Authorization: Bearer <token>.
Ad Groups
Create ad group (Swagger)
Campaign ID to create the ad group in.
Ad group name (1-256 characters).
One of:
SEARCH_STANDARD, DISPLAY_STANDARD, SHOPPING_PRODUCT_ADS.Initial status:
ENABLED or PAUSED.Default CPC bid in micros (1,000,000 = $1.00). Must be > 0.
AdGroupMutationResult
Update ad group status (Swagger)
New status:
ENABLED or PAUSED.Delete ad group (Swagger)
Ads (Responsive Search Ads)
Create RSA (Swagger)
Ad group to create the RSA in.
Landing page URL.
3-15 headlines. Each has
text (required) and optional pinned_field
(HEADLINE_1, HEADLINE_2, etc.).2-4 descriptions. Same structure as headlines.
Max 15 characters.
Max 15 characters.
Optional mobile-specific landing page.
Optional tracking template.
AdMutationResult
Update RSA (Swagger)
headlines or
descriptions are provided, they replace all existing assets.
Delete ad (Swagger)
ad_group_id and ad_id are required in the path.
Keywords
Create keywords (Swagger)
Ad group to add keywords to.
Array of keywords. Each has:
text(string, required) — keyword textmatch_type(string, default"PHRASE") —EXACT,PHRASE, orBROAD
BatchKeywordOperationResponseSchema (same as existing batch keyword response).
Update keyword (Swagger)
ENABLED or PAUSED.New CPC bid in micros. Must be > 0.
KeywordMutationResult
Remove keywords (batch) (Swagger)
BatchKeywordOperationRequestSchema as the existing batch endpoint.
Ad Schedule
Add ad schedule entries (Swagger)
Campaign to add schedule to.
Schedule entries. Each entry has:
day_of_week(string) —MONDAY,TUESDAY, …SUNDAYstart_hour(int, 0-23)start_minute(int, default 0) — 0, 15, 30, or 45end_hour(int, 0-24)end_minute(int, default 0) — 0, 15, 30, or 45
CriteriaMutationResult
Replace all ad schedule entries (Swagger)
Delete ad schedule entries (Swagger)
Campaign owning the criteria.
Resource names of schedule criteria to remove.
Location Targeting
Add locations (Swagger)
Campaign to add locations to.
Array of locations. Each has:
geo_target_constant_id(integer) — Google Ads geo target constant IDtarget_type(string, default"INCLUDE") —INCLUDEorEXCLUDE
CriteriaMutationResult
Replace all locations (Swagger)
Delete location targeting (Swagger)
campaign_id + resource_names).
Live Campaign Editing
These endpoints allow reading and updating settings on already-published (live) Google Ads campaigns, under the/api/v1/campaigns/live/ prefix.
Get campaign settings (Swagger)
Update campaign settings (Swagger)
New campaign name (1-256 characters).
ENABLED or PAUSED. Cannot set to REMOVED — use DELETE.New daily budget in micros.
New bidding strategy configuration.
Search/display network settings.
Replace-all — sets exactly these language IDs.
Replace-all — sets exactly these locations.
Replace-all — sets exactly this schedule.
Campaign start date.
Campaign end date.
Replace-all — sets exactly these conversion goals.
UpdateCampaignResultSchema
Delete campaign (Swagger)
204 No Content on success. This is irreversible — the campaign and
all child resources (ad groups, keywords, ads) will be removed.
Error handling
All mutation endpoints return consistent error shapes:Single-resource mutations
AdGroupMutationResult, AdMutationResult, KeywordMutationResult:
Batch/criteria mutations
CriteriaMutationResult:
Common HTTP errors
| Status | Cause |
|---|---|
401 | Missing or invalid auth token |
404 | Customer or resource not found |
400 | Google Ads API rejected the mutation |
502 | Google Ads API call failed unexpectedly |
Migration checklist
Implement server-side search
This is likely the biggest FE task. Add per-table search bars and optionally
a global
Cmd+K search dialog. See the
implementation guide above for patterns
(debounce, race-condition guard, progressive loading) and the
admin.cattix.com reference code.Handle PAUSED resources in data tables
Data tables now return both ENABLED and PAUSED campaigns, ad groups, and
keywords. Add status badges or visual distinction for paused items.
Build CRUD UI for ad groups, ads, keywords
Use the new management endpoints to implement create/edit/delete actions
in data tables.
Build campaign edit page
Use
GET /campaigns/live/{cid}/{campaign_id} to populate the edit form
and PATCH to save changes.Add campaign_id filter to ads table
The
/ads endpoint now supports ?campaign_id= for filtering. Use this
when showing ads within a specific campaign.