late-sdk 0.0.856 → 0.0.857

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -2
  3. data/docs/AdCampaignsApi.md +364 -6
  4. data/docs/{ListAdKeywords200ResponseKeywordsInner.md → AdKeyword.md} +7 -3
  5. data/docs/AdKeywordMetrics.md +30 -0
  6. data/docs/AddAdKeywords201Response.md +18 -0
  7. data/docs/AddAdKeywordsRequest.md +24 -0
  8. data/docs/AddAdKeywordsRequestKeywordsInner.md +20 -0
  9. data/docs/AddAdKeywordsRequestKeywordsInnerAnyOf.md +20 -0
  10. data/docs/CreateStandaloneAdRequest.md +4 -2
  11. data/docs/KeywordEntry.md +49 -0
  12. data/docs/ListAdKeywords200Response.md +1 -1
  13. data/docs/ListCampaignNegativeKeywords200Response.md +18 -0
  14. data/docs/ListCampaignNegativeKeywords200ResponseKeywordsInner.md +22 -0
  15. data/docs/RemoveAdKeyword200Response.md +20 -0
  16. data/docs/ReplaceCampaignNegativeKeywords200Response.md +22 -0
  17. data/docs/ReplaceCampaignNegativeKeywordsRequest.md +20 -0
  18. data/docs/UpdateAdKeyword200Response.md +18 -0
  19. data/docs/{UpdateAdStatusRequest.md → UpdateAdKeywordRequest.md} +2 -2
  20. data/lib/zernio-sdk/api/ad_campaigns_api.rb +358 -9
  21. data/lib/zernio-sdk/models/{list_ad_keywords200_response_keywords_inner.rb → ad_keyword.rb} +28 -8
  22. data/lib/zernio-sdk/models/ad_keyword_metrics.rb +207 -0
  23. data/lib/zernio-sdk/models/add_ad_keywords201_response.rb +149 -0
  24. data/lib/zernio-sdk/models/add_ad_keywords_request.rb +250 -0
  25. data/lib/zernio-sdk/models/add_ad_keywords_request_keywords_inner.rb +103 -0
  26. data/lib/zernio-sdk/models/add_ad_keywords_request_keywords_inner_any_of.rb +225 -0
  27. data/lib/zernio-sdk/models/create_standalone_ad_request.rb +55 -5
  28. data/lib/zernio-sdk/models/keyword_entry.rb +105 -0
  29. data/lib/zernio-sdk/models/list_ad_keywords200_response.rb +1 -1
  30. data/lib/zernio-sdk/models/list_campaign_negative_keywords200_response.rb +149 -0
  31. data/lib/zernio-sdk/models/list_campaign_negative_keywords200_response_keywords_inner.rb +199 -0
  32. data/lib/zernio-sdk/models/remove_ad_keyword200_response.rb +157 -0
  33. data/lib/zernio-sdk/models/replace_campaign_negative_keywords200_response.rb +170 -0
  34. data/lib/zernio-sdk/models/replace_campaign_negative_keywords_request.rb +219 -0
  35. data/lib/zernio-sdk/models/update_ad_keyword200_response.rb +147 -0
  36. data/lib/zernio-sdk/models/{update_ad_status_request.rb → update_ad_keyword_request.rb} +3 -3
  37. data/lib/zernio-sdk/version.rb +1 -1
  38. data/lib/zernio-sdk.rb +14 -2
  39. data/openapi.yaml +257 -21
  40. data/spec/api/ad_campaigns_api_spec.rb +64 -1
  41. data/spec/models/ad_keyword_metrics_spec.rb +72 -0
  42. data/spec/models/{list_ad_keywords200_response_keywords_inner_spec.rb → ad_keyword_spec.rb} +18 -6
  43. data/spec/models/add_ad_keywords201_response_spec.rb +36 -0
  44. data/spec/models/add_ad_keywords_request_keywords_inner_any_of_spec.rb +46 -0
  45. data/spec/models/add_ad_keywords_request_keywords_inner_spec.rb +21 -0
  46. data/spec/models/add_ad_keywords_request_spec.rb +54 -0
  47. data/spec/models/create_standalone_ad_request_spec.rb +6 -0
  48. data/spec/models/keyword_entry_spec.rb +32 -0
  49. data/spec/models/list_campaign_negative_keywords200_response_keywords_inner_spec.rb +52 -0
  50. data/spec/models/list_campaign_negative_keywords200_response_spec.rb +36 -0
  51. data/spec/models/remove_ad_keyword200_response_spec.rb +42 -0
  52. data/spec/models/replace_campaign_negative_keywords200_response_spec.rb +48 -0
  53. data/spec/models/replace_campaign_negative_keywords_request_spec.rb +46 -0
  54. data/spec/models/update_ad_keyword200_response_spec.rb +36 -0
  55. data/spec/models/{update_ad_status_request_spec.rb → update_ad_keyword_request_spec.rb} +6 -6
  56. data/zernio-sdk-0.0.857.gem +0 -0
  57. metadata +58 -10
  58. data/zernio-sdk-0.0.856.gem +0 -0
data/openapi.yaml CHANGED
@@ -9182,6 +9182,49 @@ components:
9182
9182
  page_id: { type: string }
9183
9183
  earliestAd: { type: string, format: date-time }
9184
9184
  latestAd: { type: string, format: date-time }
9185
+ AdKeyword:
9186
+ type: object
9187
+ properties:
9188
+ id: { type: string }
9189
+ accountId: { type: string, description: Social account ID owning the sync }
9190
+ profileId: { type: string }
9191
+ platform: { type: string, enum: [google] }
9192
+ adAccountId: { type: string, description: Google customer ID }
9193
+ campaignId: { type: string }
9194
+ campaignName: { type: [string, "null"] }
9195
+ campaignStatus: { type: [string, "null"] }
9196
+ adSetId: { type: string, description: Google ad group ID }
9197
+ adSetName: { type: [string, "null"] }
9198
+ adSetStatus: { type: [string, "null"] }
9199
+ keyword: { type: string }
9200
+ matchType: { type: string, enum: [exact, phrase, broad, unknown] }
9201
+ status: { type: string, enum: [active, paused] }
9202
+ negative: { type: boolean }
9203
+ qualityScore: { type: [integer, "null"], description: 'Google Quality Score, 1-10. Null when unrated.' }
9204
+ syncedAt: { type: [string, "null"], format: date-time }
9205
+ metrics:
9206
+ type: [object, "null"]
9207
+ description: 'Trailing 30-day window. Null on rows synced before the metrics columns existed (re-synced on the keyword''s next weekly sweep).'
9208
+ properties:
9209
+ windowDays: { type: integer }
9210
+ clicks: { type: integer }
9211
+ impressions: { type: integer }
9212
+ cost: { type: number, description: 'Account currency, not USD-normalized' }
9213
+ conversions: { type: number }
9214
+ firstPageCpc: { type: [number, "null"], description: Account currency }
9215
+ firstPositionCpc: { type: [number, "null"], description: Account currency }
9216
+ KeywordEntry:
9217
+ description: 'A Google Search keyword: a bare string (BROAD match), or an object naming the match type.'
9218
+ oneOf:
9219
+ - type: string
9220
+ minLength: 1
9221
+ maxLength: 80
9222
+ description: 'Keyword text; defaults to BROAD match'
9223
+ - type: object
9224
+ required: [text]
9225
+ properties:
9226
+ text: { type: string, minLength: 1, maxLength: 80 }
9227
+ matchType: { type: string, enum: [exact, phrase, broad] }
9185
9228
  ConversionEvent:
9186
9229
  type: object
9187
9230
  description: |
@@ -41308,30 +41351,126 @@ paths:
41308
41351
  properties:
41309
41352
  keywords:
41310
41353
  type: array
41311
- items:
41312
- type: object
41313
- properties:
41314
- id: { type: string }
41315
- accountId: { type: string, description: Social account ID owning the sync }
41316
- profileId: { type: string }
41317
- platform: { type: string, enum: [google] }
41318
- adAccountId: { type: string, description: Google customer ID }
41319
- campaignId: { type: string }
41320
- campaignName: { type: [string, "null"] }
41321
- campaignStatus: { type: [string, "null"] }
41322
- adSetId: { type: string, description: Google ad group ID }
41323
- adSetName: { type: [string, "null"] }
41324
- adSetStatus: { type: [string, "null"] }
41325
- keyword: { type: string }
41326
- matchType: { type: string, enum: [exact, phrase, broad, unknown] }
41327
- status: { type: string, enum: [active, paused] }
41328
- negative: { type: boolean }
41329
- syncedAt: { type: [string, "null"], format: date-time }
41354
+ items: { $ref: '#/components/schemas/AdKeyword' }
41330
41355
  pagination: { $ref: '#/components/schemas/Pagination' }
41331
41356
  '400': { $ref: '#/components/responses/BadRequest' }
41332
41357
  '401': { $ref: '#/components/responses/Unauthorized' }
41333
41358
  '403':
41334
41359
  description: Ads access required. Legacy plans need the Ads add-on; included by default on usage-based plans.
41360
+ post:
41361
+ x-resource-group: "ads"
41362
+ operationId: addAdKeywords
41363
+ tags: ["Ad Campaigns"]
41364
+ x-platforms: ["google"]
41365
+ summary: Add Search keywords to an ad group
41366
+ description: |
41367
+ Adds one or more keyword criteria to an existing Google Search ad group,
41368
+ without touching the keywords already there (unlike the whole-set diff on
41369
+ `PUT /v1/ads/{adId}`, `keywords`/`negativeKeywords` in `platformSpecificData`,
41370
+ which replaces the set). Set `negative: true` to add ad-group-level negatives
41371
+ instead of positive keywords.
41372
+ security:
41373
+ - bearerAuth: []
41374
+ requestBody:
41375
+ required: true
41376
+ content:
41377
+ application/json:
41378
+ schema:
41379
+ type: object
41380
+ required: [accountId, adSetId, keywords]
41381
+ properties:
41382
+ accountId: { type: string, description: Social account ID (Google Ads) }
41383
+ adSetId: { type: string, description: Google ad group ID to add the keywords to }
41384
+ keywords:
41385
+ type: array
41386
+ minItems: 1
41387
+ maxItems: 1000
41388
+ items:
41389
+ anyOf:
41390
+ - type: string
41391
+ description: 'Keyword text; defaults to BROAD match'
41392
+ - type: object
41393
+ required: [text]
41394
+ properties:
41395
+ text: { type: string, minLength: 1, maxLength: 80 }
41396
+ matchType: { type: string, enum: [exact, phrase, broad] }
41397
+ negative: { type: boolean, default: false, description: 'Add as ad-group-level negatives instead of positive keywords' }
41398
+ responses:
41399
+ '201':
41400
+ description: Keywords added
41401
+ content:
41402
+ application/json:
41403
+ schema:
41404
+ type: object
41405
+ properties:
41406
+ keywords:
41407
+ type: array
41408
+ items: { $ref: '#/components/schemas/AdKeyword' }
41409
+ '400': { $ref: '#/components/responses/BadRequest' }
41410
+ '401': { $ref: '#/components/responses/Unauthorized' }
41411
+ '404': { description: 'The ad group ("adSetId") was not found for this account.' }
41412
+ '501': { description: Only available on Google Ads accounts }
41413
+
41414
+ /v1/ads/keywords/{keywordId}:
41415
+ patch:
41416
+ x-resource-group: "ads"
41417
+ operationId: updateAdKeyword
41418
+ tags: ["Ad Campaigns"]
41419
+ x-platforms: ["google"]
41420
+ summary: Pause or enable a Search keyword
41421
+ description: |
41422
+ Changes `ad_group_criterion.status` for one keyword criterion (M.140).
41423
+ Negative keywords have no status on Google and cannot be paused or enabled.
41424
+ security:
41425
+ - bearerAuth: []
41426
+ parameters:
41427
+ - { name: keywordId, in: path, required: true, schema: { type: string }, description: Zernio keyword ID (not the Google criterion ID) }
41428
+ requestBody:
41429
+ required: true
41430
+ content:
41431
+ application/json:
41432
+ schema:
41433
+ type: object
41434
+ required: [status]
41435
+ properties:
41436
+ status: { type: string, enum: [active, paused] }
41437
+ responses:
41438
+ '200':
41439
+ description: Keyword updated
41440
+ content:
41441
+ application/json:
41442
+ schema:
41443
+ type: object
41444
+ properties:
41445
+ keyword: { $ref: '#/components/schemas/AdKeyword' }
41446
+ '400': { $ref: '#/components/responses/BadRequest' }
41447
+ '401': { $ref: '#/components/responses/Unauthorized' }
41448
+ '404': { description: Keyword not found }
41449
+ '422': { description: 'Negative keywords have no status on Google; they cannot be paused or enabled.' }
41450
+ delete:
41451
+ x-resource-group: "ads"
41452
+ operationId: removeAdKeyword
41453
+ tags: ["Ad Campaigns"]
41454
+ x-platforms: ["google"]
41455
+ summary: Remove a Search keyword
41456
+ description: Removes one keyword criterion (positive or negative) from its ad group (M.140).
41457
+ security:
41458
+ - bearerAuth: []
41459
+ parameters:
41460
+ - { name: keywordId, in: path, required: true, schema: { type: string }, description: Zernio keyword ID (not the Google criterion ID) }
41461
+ responses:
41462
+ '200':
41463
+ description: Keyword removed
41464
+ content:
41465
+ application/json:
41466
+ schema:
41467
+ type: object
41468
+ properties:
41469
+ removed: { type: boolean, description: Always true on success }
41470
+ keywordId: { type: string }
41471
+ '400': { $ref: '#/components/responses/BadRequest' }
41472
+ '401': { $ref: '#/components/responses/Unauthorized' }
41473
+ '404': { description: Keyword not found }
41335
41474
 
41336
41475
  /v1/ads/campaigns:
41337
41476
  get:
@@ -41653,6 +41792,102 @@ paths:
41653
41792
  '404': { description: Campaign not found }
41654
41793
  '501': { description: Operation not supported on this platform }
41655
41794
 
41795
+ /v1/ads/campaigns/{campaignId}/negative-keywords:
41796
+ get:
41797
+ x-resource-group: "ads"
41798
+ operationId: listCampaignNegativeKeywords
41799
+ tags: ["Ad Campaigns"]
41800
+ x-platforms: ["google"]
41801
+ summary: List campaign-level negative keywords
41802
+ description: |
41803
+ Returns the campaign-level negative keywords (`campaign_criterion.negative`),
41804
+ distinct from the ad-group-level negatives under `GET /v1/ads/keywords`. Read
41805
+ live from Google on every call (not synced to Postgres), and gated by the
41806
+ shared Google Ads operations budget like every other on-demand Google surface.
41807
+
41808
+ The platform is always discovered from the campaign itself; a non-Google
41809
+ campaign returns 501 rather than 404, whether or not `platform` was passed.
41810
+ security:
41811
+ - bearerAuth: []
41812
+ parameters:
41813
+ - { name: campaignId, in: path, required: true, schema: { type: string }, description: Platform campaign ID }
41814
+ - { name: platform, in: query, schema: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai] }, description: 'Optional and NOT authoritative: the resolved campaign''s own platform decides 200 vs 501, never this hint.' }
41815
+ responses:
41816
+ '200':
41817
+ description: Campaign-level negative keywords
41818
+ content:
41819
+ application/json:
41820
+ schema:
41821
+ type: object
41822
+ properties:
41823
+ keywords:
41824
+ type: array
41825
+ items:
41826
+ type: object
41827
+ properties:
41828
+ criterionId: { type: string }
41829
+ text: { type: string }
41830
+ matchType: { type: string, enum: [exact, phrase, broad] }
41831
+ '401': { $ref: '#/components/responses/Unauthorized' }
41832
+ '404': { description: Campaign not found }
41833
+ '429': { description: Google Ads operations budget exhausted; retry later }
41834
+ '501': { description: Only available on Google Ads campaigns }
41835
+ put:
41836
+ x-resource-group: "ads"
41837
+ operationId: replaceCampaignNegativeKeywords
41838
+ tags: ["Ad Campaigns"]
41839
+ x-platforms: ["google"]
41840
+ summary: Replace campaign-level negative keywords
41841
+ description: |
41842
+ Replaces the FULL set of campaign-level negative keywords (C.270): the desired
41843
+ list is diffed against what Google already has, and the difference is applied
41844
+ as one `create`/`remove` mutate. Send an empty array to clear every campaign
41845
+ negative.
41846
+
41847
+ The platform is always discovered from the campaign itself; a non-Google
41848
+ campaign returns 501 rather than 404, whether or not `platform` was sent.
41849
+ security:
41850
+ - bearerAuth: []
41851
+ parameters:
41852
+ - { name: campaignId, in: path, required: true, schema: { type: string }, description: Platform campaign ID }
41853
+ requestBody:
41854
+ required: true
41855
+ content:
41856
+ application/json:
41857
+ schema:
41858
+ type: object
41859
+ required: [keywords]
41860
+ properties:
41861
+ platform: { type: string, enum: [facebook, instagram, tiktok, linkedin, pinterest, google, twitter, openai], description: 'Optional and NOT authoritative: the resolved campaign''s own platform decides 200 vs 501, never this hint.' }
41862
+ keywords:
41863
+ type: array
41864
+ maxItems: 1000
41865
+ items: { $ref: '#/components/schemas/KeywordEntry' }
41866
+ responses:
41867
+ '200':
41868
+ description: Campaign-level negative keywords replaced
41869
+ content:
41870
+ application/json:
41871
+ schema:
41872
+ type: object
41873
+ properties:
41874
+ created: { type: integer, description: Negative criteria newly created on Google }
41875
+ removed: { type: integer, description: Negative criteria removed from Google }
41876
+ keywords:
41877
+ type: array
41878
+ description: The full negative-keyword set after the replace
41879
+ items:
41880
+ type: object
41881
+ properties:
41882
+ criterionId: { type: string }
41883
+ text: { type: string }
41884
+ matchType: { type: string, enum: [exact, phrase, broad] }
41885
+ '400': { $ref: '#/components/responses/BadRequest' }
41886
+ '401': { $ref: '#/components/responses/Unauthorized' }
41887
+ '404': { description: Campaign not found }
41888
+ '429': { description: Google Ads operations budget exhausted; retry later }
41889
+ '501': { description: Only available on Google Ads campaigns }
41890
+
41656
41891
  /v1/ads/campaigns/bulk-status:
41657
41892
  post:
41658
41893
  x-resource-group: "ads"
@@ -45586,8 +45821,9 @@ paths:
45586
45821
  items: { type: string, enum: [mobile, desktop] }
45587
45822
  audienceId: { type: string, description: Custom audience ID for targeting }
45588
45823
  campaignType: { type: string, enum: [display, search], default: display, description: Google only }
45589
- keywords: { type: array, maxItems: 1000, items: { type: string, maxLength: 80 }, description: "Google Search only. BROAD-match keywords on the new ad group. Editable later via PUT /v1/ads/{adId} targeting.keywords, which also sets match types." }
45590
- negativeKeywords: { type: array, items: { type: string, maxLength: 80 }, description: "Google Search only; other platforms return 400. BROAD-match negative keywords on the new ad group. Editable later via PUT /v1/ads/{adId} targeting.negativeKeywords." }
45824
+ keywords: { type: array, maxItems: 1000, items: { $ref: '#/components/schemas/KeywordEntry' }, description: "Google Search only. Keywords on the new ad group; entries are strings (BROAD) or { text, matchType }. Editable later via PUT /v1/ads/{adId} targeting.keywords." }
45825
+ negativeKeywords: { type: array, maxItems: 1000, items: { $ref: '#/components/schemas/KeywordEntry' }, description: "Google Search only; other platforms return 400. Ad-group-level negative keywords on the new ad group. Editable later via PUT /v1/ads/{adId} targeting.negativeKeywords." }
45826
+ campaignNegativeKeywords: { type: array, maxItems: 1000, items: { $ref: '#/components/schemas/KeywordEntry' }, description: "Google Search only; other platforms return 400. Campaign-level negative keywords (campaign_criterion.negative), created alongside the ad group. Editable later via PUT /v1/ads/campaigns/{campaignId}/negative-keywords." }
45591
45827
  additionalHeadlines: { type: array, items: { type: string }, description: "Google Search RSA only. Extra headlines." }
45592
45828
  additionalDescriptions: { type: array, items: { type: string }, description: "Google Search RSA only. Extra descriptions." }
45593
45829
  sitelinks:
@@ -32,6 +32,18 @@ describe 'AdCampaignsApi' do
32
32
  end
33
33
  end
34
34
 
35
+ # unit tests for add_ad_keywords
36
+ # Add Search keywords to an ad group
37
+ # Adds one or more keyword criteria to an existing Google Search ad group, without touching the keywords already there (unlike the whole-set diff on `PUT /v1/ads/{adId}`, `keywords`/`negativeKeywords` in `platformSpecificData`, which replaces the set). Set `negative: true` to add ad-group-level negatives instead of positive keywords.
38
+ # @param add_ad_keywords_request
39
+ # @param [Hash] opts the optional parameters
40
+ # @return [AddAdKeywords201Response]
41
+ describe 'add_ad_keywords test' do
42
+ it 'should work' do
43
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
44
+ end
45
+ end
46
+
35
47
  # unit tests for attach_campaign_assets
36
48
  # Attach extension assets to a Google Search campaign
37
49
  # Attach sitelinks, callouts and/or structured snippets to an already-existing Google Search campaign — the same builders POST /v1/ads/create uses, but without rebuilding the hierarchy. At least one of sitelinks, callouts or structuredSnippets is required. Google-only. Other platforms have no equivalent extension surface and return 501. Approval status is Google-async; poll `asset.policy_summary` after review. Assets stay in the account library even if the campaign is later deleted.
@@ -319,6 +331,44 @@ describe 'AdCampaignsApi' do
319
331
  end
320
332
  end
321
333
 
334
+ # unit tests for list_campaign_negative_keywords
335
+ # List campaign-level negative keywords
336
+ # Returns the campaign-level negative keywords (`campaign_criterion.negative`), distinct from the ad-group-level negatives under `GET /v1/ads/keywords`. Read live from Google on every call (not synced to Postgres), and gated by the shared Google Ads operations budget like every other on-demand Google surface. The platform is always discovered from the campaign itself; a non-Google campaign returns 501 rather than 404, whether or not `platform` was passed.
337
+ # @param campaign_id Platform campaign ID
338
+ # @param [Hash] opts the optional parameters
339
+ # @option opts [String] :platform Optional and NOT authoritative: the resolved campaign's own platform decides 200 vs 501, never this hint.
340
+ # @return [ListCampaignNegativeKeywords200Response]
341
+ describe 'list_campaign_negative_keywords test' do
342
+ it 'should work' do
343
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
344
+ end
345
+ end
346
+
347
+ # unit tests for remove_ad_keyword
348
+ # Remove a Search keyword
349
+ # Removes one keyword criterion (positive or negative) from its ad group (M.140).
350
+ # @param keyword_id Zernio keyword ID (not the Google criterion ID)
351
+ # @param [Hash] opts the optional parameters
352
+ # @return [RemoveAdKeyword200Response]
353
+ describe 'remove_ad_keyword test' do
354
+ it 'should work' do
355
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
356
+ end
357
+ end
358
+
359
+ # unit tests for replace_campaign_negative_keywords
360
+ # Replace campaign-level negative keywords
361
+ # Replaces the FULL set of campaign-level negative keywords (C.270): the desired list is diffed against what Google already has, and the difference is applied as one `create`/`remove` mutate. Send an empty array to clear every campaign negative. The platform is always discovered from the campaign itself; a non-Google campaign returns 501 rather than 404, whether or not `platform` was sent.
362
+ # @param campaign_id Platform campaign ID
363
+ # @param replace_campaign_negative_keywords_request
364
+ # @param [Hash] opts the optional parameters
365
+ # @return [ReplaceCampaignNegativeKeywords200Response]
366
+ describe 'replace_campaign_negative_keywords test' do
367
+ it 'should work' do
368
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
369
+ end
370
+ end
371
+
322
372
  # unit tests for update_ad
323
373
  # Update ad
324
374
  # Patch one or more fields on an ad. Status, budget, targeting, and creative changes are propagated to the platform. Per-platform support: - **Meta** (Facebook + Instagram): all fields supported. - **TikTok**: status, budget, targeting (via `/v2/adgroup/update/`), and creative (via `/v2/ad/update/` patch-style — `headline` is ignored, `body` becomes `ad_text`). - **Google**: status, budget, and KEYWORD edits via `targeting.keywords` / `targeting.negativeKeywords` — each list you send becomes the FULL new set of its kind on the ad group (criteria not in the list are removed); a kind left out is untouched. Any other `targeting` field returns 400: Google cannot mutate broad targeting post-create without recreating the campaign. `creative` returns 501. - **LinkedIn**: status, budget, targeting (geo countries only, applied to the LinkedIn Campaign via PARTIAL_UPDATE), and creative (uploads new media, creates a replacement inline creative on the same campaign, pauses the old one). - **Pinterest / X / OpenAI Ads**: status + budget only. Sending `targeting` or `creative` returns 501 with code `unsupported_platform_operation`. OpenAI Ads budget is lifetime-only (see `budget.type` below).
@@ -358,6 +408,19 @@ describe 'AdCampaignsApi' do
358
408
  end
359
409
  end
360
410
 
411
+ # unit tests for update_ad_keyword
412
+ # Pause or enable a Search keyword
413
+ # Changes `ad_group_criterion.status` for one keyword criterion (M.140). Negative keywords have no status on Google and cannot be paused or enabled.
414
+ # @param keyword_id Zernio keyword ID (not the Google criterion ID)
415
+ # @param update_ad_keyword_request
416
+ # @param [Hash] opts the optional parameters
417
+ # @return [UpdateAdKeyword200Response]
418
+ describe 'update_ad_keyword test' do
419
+ it 'should work' do
420
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
421
+ end
422
+ end
423
+
361
424
  # unit tests for update_ad_set
362
425
  # Update an ad set
363
426
  # Ad-set-level writes. Use this for ABO budget updates, ad-set-scoped pause/resume, bid-strategy edits, Meta value-rule-set attach/detach, and Meta-only post-launch delivery settings via `platformSpecificData`. At least one updatable field is required. Value rule sets (Meta only, see `/v1/ads/value-rule-sets`): - ATTACH or REPLACE: send `valueRuleSetId`. Attachment is driven by the id's presence, so `valueRulesApplied: true` is optional. Sending a different id replaces the previous association; there is no separate replace call. - DETACH: send `valueRulesApplied: false` and OMIT `valueRuleSetId`. - Sending `valueRulesApplied: false` TOGETHER with `valueRuleSetId` returns 400 `mutually_exclusive_fields`. This is deliberate: Meta attaches the rule set whenever `value_rule_set_id` is present, even with `value_rules_applied` false, so echoing stored state while asking to detach would silently keep the bid adjustments live. - Eligibility: only ad sets on `LOWEST_COST_WITHOUT_CAP` or `COST_CAP`. Meta rejects the rest server-side. - Read back with `GET /v1/ads/ad-sets/{adSetId}?fields=value_rule_set_id`. Meta does not document `value_rules_applied` as a readable ad-set field, so the boolean cannot be read back. Bid strategy compatibility (per Meta's spec): - `LOWEST_COST_WITHOUT_CAP`: no `bidAmount`, no `roasAverageFloor`. - `LOWEST_COST_WITH_BID_CAP` / `COST_CAP`: `bidAmount` REQUIRED (whole currency units). - `LOWEST_COST_WITH_MIN_ROAS`: `roasAverageFloor` REQUIRED (decimal multiplier, e.g. 2.0 = 2.0x ROAS). - Meta only: send `bidAmount` WITHOUT `bidStrategy` to change the cap amount on an ad set under a COST_CAP / LOWEST_COST_WITH_BID_CAP parent campaign, leaving the strategy itself (inherited from the campaign) untouched. `roasAverageFloor` without `bidStrategy` is rejected (it has no meaning outside LOWEST_COST_WITH_MIN_ROAS). Delivery settings are validated by Meta against the campaign objective; incompatible combinations (e.g. a billingEvent the optimization goal doesn't allow) surface as 400s from Meta. When updating `budget` on an ABO campaign: if the parent campaign is CBO, the response is 409 with code BUDGET_LEVEL_MISMATCH — route to PUT /v1/ads/campaigns/{campaignId} instead.
@@ -388,7 +451,7 @@ describe 'AdCampaignsApi' do
388
451
  # Pause or resume a single ad
389
452
  # Ad-scoped pause/resume — touches ONLY this ad, never its parent ad set or campaign (so sibling ads keep running). Thin wrapper over the `status` field of PUT /v1/ads/{adId}, for callers that want a URL symmetric to /v1/ads/campaigns/{campaignId}/status and /v1/ads/ad-sets/{adSetId}/status. `{adId}` accepts the same identifier dialects as GET/PUT /v1/ads/{adId} (Zernio hex `_id`, Meta numeric `platformAdId`, or the creative's effective story/media IDs). `platform` is inferred from the ad, so it's not required in the body. Ads in terminal statuses (rejected, completed, cancelled) and no-op flips (already in the target state) are skipped.
390
453
  # @param ad_id Zernio `_id` (hex), Meta `platformAdId` (numeric), or one of the creative's effective story/media IDs.
391
- # @param update_ad_status_request
454
+ # @param update_ad_keyword_request
392
455
  # @param [Hash] opts the optional parameters
393
456
  # @return [UpdateAdStatus200Response]
394
457
  describe 'update_ad_status test' do
@@ -0,0 +1,72 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for Zernio::AdKeywordMetrics
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::AdKeywordMetrics do
21
+ #let(:instance) { Zernio::AdKeywordMetrics.new }
22
+
23
+ describe 'test an instance of AdKeywordMetrics' do
24
+ it 'should create an instance of AdKeywordMetrics' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(Zernio::AdKeywordMetrics)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "window_days"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ end
34
+ end
35
+
36
+ describe 'test attribute "clicks"' do
37
+ it 'should work' do
38
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
39
+ end
40
+ end
41
+
42
+ describe 'test attribute "impressions"' do
43
+ it 'should work' do
44
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
45
+ end
46
+ end
47
+
48
+ describe 'test attribute "cost"' do
49
+ it 'should work' do
50
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
51
+ end
52
+ end
53
+
54
+ describe 'test attribute "conversions"' do
55
+ it 'should work' do
56
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
57
+ end
58
+ end
59
+
60
+ describe 'test attribute "first_page_cpc"' do
61
+ it 'should work' do
62
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
63
+ end
64
+ end
65
+
66
+ describe 'test attribute "first_position_cpc"' do
67
+ it 'should work' do
68
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
69
+ end
70
+ end
71
+
72
+ end
@@ -14,16 +14,16 @@ require 'spec_helper'
14
14
  require 'json'
15
15
  require 'date'
16
16
 
17
- # Unit tests for Zernio::ListAdKeywords200ResponseKeywordsInner
17
+ # Unit tests for Zernio::AdKeyword
18
18
  # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
19
  # Please update as you see appropriate
20
- describe Zernio::ListAdKeywords200ResponseKeywordsInner do
21
- #let(:instance) { Zernio::ListAdKeywords200ResponseKeywordsInner.new }
20
+ describe Zernio::AdKeyword do
21
+ #let(:instance) { Zernio::AdKeyword.new }
22
22
 
23
- describe 'test an instance of ListAdKeywords200ResponseKeywordsInner' do
24
- it 'should create an instance of ListAdKeywords200ResponseKeywordsInner' do
23
+ describe 'test an instance of AdKeyword' do
24
+ it 'should create an instance of AdKeyword' do
25
25
  # uncomment below to test the instance creation
26
- #expect(instance).to be_instance_of(Zernio::ListAdKeywords200ResponseKeywordsInner)
26
+ #expect(instance).to be_instance_of(Zernio::AdKeyword)
27
27
  end
28
28
  end
29
29
 
@@ -129,10 +129,22 @@ describe Zernio::ListAdKeywords200ResponseKeywordsInner do
129
129
  end
130
130
  end
131
131
 
132
+ describe 'test attribute "quality_score"' do
133
+ it 'should work' do
134
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
135
+ end
136
+ end
137
+
132
138
  describe 'test attribute "synced_at"' do
133
139
  it 'should work' do
134
140
  # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
135
141
  end
136
142
  end
137
143
 
144
+ describe 'test attribute "metrics"' do
145
+ it 'should work' do
146
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
147
+ end
148
+ end
149
+
138
150
  end
@@ -0,0 +1,36 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for Zernio::AddAdKeywords201Response
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::AddAdKeywords201Response do
21
+ #let(:instance) { Zernio::AddAdKeywords201Response.new }
22
+
23
+ describe 'test an instance of AddAdKeywords201Response' do
24
+ it 'should create an instance of AddAdKeywords201Response' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(Zernio::AddAdKeywords201Response)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "keywords"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,46 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for Zernio::AddAdKeywordsRequestKeywordsInnerAnyOf
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::AddAdKeywordsRequestKeywordsInnerAnyOf do
21
+ #let(:instance) { Zernio::AddAdKeywordsRequestKeywordsInnerAnyOf.new }
22
+
23
+ describe 'test an instance of AddAdKeywordsRequestKeywordsInnerAnyOf' do
24
+ it 'should create an instance of AddAdKeywordsRequestKeywordsInnerAnyOf' do
25
+ # uncomment below to test the instance creation
26
+ #expect(instance).to be_instance_of(Zernio::AddAdKeywordsRequestKeywordsInnerAnyOf)
27
+ end
28
+ end
29
+
30
+ describe 'test attribute "text"' do
31
+ it 'should work' do
32
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
33
+ end
34
+ end
35
+
36
+ describe 'test attribute "match_type"' do
37
+ it 'should work' do
38
+ # assertion here. ref: https://rspec.info/features/3-12/rspec-expectations/built-in-matchers/
39
+ # validator = Petstore::EnumTest::EnumAttributeValidator.new('String', ["exact", "phrase", "broad"])
40
+ # validator.allowable_values.each do |value|
41
+ # expect { instance.match_type = value }.not_to raise_error
42
+ # end
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,21 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'spec_helper'
14
+ require 'json'
15
+ require 'date'
16
+
17
+ # Unit tests for Zernio::AddAdKeywordsRequestKeywordsInner
18
+ # Automatically generated by openapi-generator (https://openapi-generator.tech)
19
+ # Please update as you see appropriate
20
+ describe Zernio::AddAdKeywordsRequestKeywordsInner do
21
+ end