late-sdk 0.0.900 → 0.0.902

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 (159) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +60 -6
  3. data/docs/AdAccountsApi.md +657 -19
  4. data/docs/AdCampaignsApi.md +521 -9
  5. data/docs/AdCreative.md +6 -0
  6. data/docs/AddAccountCalloutsRequest.md +3 -3
  7. data/docs/AddAccountSitelinks201Response.md +20 -0
  8. data/docs/AddAccountSitelinks201ResponseSitelinksInner.md +26 -0
  9. data/docs/AddAccountSitelinksRequest.md +22 -0
  10. data/docs/AddAccountStructuredSnippets201Response.md +20 -0
  11. data/docs/AddAccountStructuredSnippets201ResponseStructuredSnippetsInner.md +22 -0
  12. data/docs/AddAccountStructuredSnippetsRequest.md +22 -0
  13. data/docs/AttachAdGroupAssets201Response.md +24 -0
  14. data/docs/AttachCampaignAssetsRequest.md +4 -4
  15. data/docs/CreateStandaloneAdRequest.md +4 -4
  16. data/docs/CreateStandaloneAdRequestAdditionalDescriptionsInner.md +49 -0
  17. data/docs/CreateStandaloneAdRequestAdditionalHeadlinesInner.md +49 -0
  18. data/docs/GetAd200Response.md +5 -1
  19. data/docs/GoogleAssetUpdate.md +26 -0
  20. data/docs/GoogleRsaDescription.md +20 -0
  21. data/docs/GoogleRsaHeadline.md +20 -0
  22. data/docs/{AttachCampaignAssetsRequestSitelinksInner.md → GoogleSitelink.md} +2 -2
  23. data/docs/{AttachCampaignAssetsRequestStructuredSnippetsInner.md → GoogleStructuredSnippet.md} +2 -2
  24. data/docs/ListAccountCallouts200Response.md +2 -2
  25. data/docs/ListAccountCallouts200ResponseCalloutsInner.md +3 -3
  26. data/docs/ListAccountSitelinks200Response.md +24 -0
  27. data/docs/ListAccountSitelinks200ResponseSitelinksInner.md +32 -0
  28. data/docs/ListAccountStructuredSnippets200Response.md +24 -0
  29. data/docs/ListAccountStructuredSnippets200ResponseStructuredSnippetsInner.md +28 -0
  30. data/docs/ListAdGroupAssets200Response.md +28 -0
  31. data/docs/ListAdGroupAssets200ResponseCalloutsInner.md +22 -0
  32. data/docs/ListAdGroupAssets200ResponseSitelinksInner.md +28 -0
  33. data/docs/ListAdGroupAssets200ResponseStructuredSnippetsInner.md +24 -0
  34. data/docs/ListCampaignAssets200Response.md +28 -0
  35. data/docs/ListCampaignAssets200ResponseCalloutsInner.md +22 -0
  36. data/docs/ListCampaignAssets200ResponseSitelinksInner.md +28 -0
  37. data/docs/ListCampaignAssets200ResponseStructuredSnippetsInner.md +24 -0
  38. data/docs/RemoveAccountCalloutRequest.md +3 -3
  39. data/docs/RemoveAdGroupAssetsRequest.md +24 -0
  40. data/docs/RemoveCampaignAssets200Response.md +18 -0
  41. data/docs/RemoveCampaignAssetsRequest.md +24 -0
  42. data/docs/UpdateAccountCallouts200Response.md +20 -0
  43. data/docs/UpdateAccountCalloutsRequest.md +22 -0
  44. data/docs/UpdateAccountCalloutsRequestUpdatesInner.md +20 -0
  45. data/docs/UpdateAccountCalloutsRequestUpdatesInnerCalloutAsset.md +18 -0
  46. data/docs/UpdateAccountSitelinksRequest.md +22 -0
  47. data/docs/UpdateAccountSitelinksRequestUpdatesInner.md +22 -0
  48. data/docs/UpdateAccountSitelinksRequestUpdatesInnerSitelinkAsset.md +24 -0
  49. data/docs/UpdateAccountStructuredSnippetsRequest.md +22 -0
  50. data/docs/UpdateAccountStructuredSnippetsRequestUpdatesInner.md +20 -0
  51. data/docs/UpdateAdRequest.md +6 -0
  52. data/docs/UpdateCampaignAssets200Response.md +18 -0
  53. data/docs/UpdateCampaignAssetsRequest.md +22 -0
  54. data/docs/WebhookEventsApi.md +2 -2
  55. data/lib/zernio-sdk/api/ad_accounts_api.rb +656 -16
  56. data/lib/zernio-sdk/api/ad_campaigns_api.rb +586 -10
  57. data/lib/zernio-sdk/api/webhook_events_api.rb +4 -4
  58. data/lib/zernio-sdk/models/ad_creative.rb +112 -1
  59. data/lib/zernio-sdk/models/add_account_callouts_request.rb +34 -3
  60. data/lib/zernio-sdk/models/add_account_sitelinks201_response.rb +158 -0
  61. data/lib/zernio-sdk/models/add_account_sitelinks201_response_sitelinks_inner.rb +267 -0
  62. data/lib/zernio-sdk/models/add_account_sitelinks_request.rb +253 -0
  63. data/lib/zernio-sdk/models/add_account_structured_snippets201_response.rb +158 -0
  64. data/lib/zernio-sdk/models/add_account_structured_snippets201_response_structured_snippets_inner.rb +229 -0
  65. data/lib/zernio-sdk/models/add_account_structured_snippets_request.rb +253 -0
  66. data/lib/zernio-sdk/models/attach_ad_group_assets201_response.rb +180 -0
  67. data/lib/zernio-sdk/models/attach_campaign_assets_request.rb +37 -5
  68. data/lib/zernio-sdk/models/create_standalone_ad_request.rb +4 -4
  69. data/lib/zernio-sdk/models/create_standalone_ad_request_additional_descriptions_inner.rb +104 -0
  70. data/lib/zernio-sdk/models/create_standalone_ad_request_additional_headlines_inner.rb +104 -0
  71. data/lib/zernio-sdk/models/get_ad200_response.rb +25 -4
  72. data/lib/zernio-sdk/models/google_asset_update.rb +234 -0
  73. data/lib/zernio-sdk/models/google_rsa_description.rb +226 -0
  74. data/lib/zernio-sdk/models/google_rsa_headline.rb +226 -0
  75. data/lib/zernio-sdk/models/{attach_campaign_assets_request_sitelinks_inner.rb → google_sitelink.rb} +3 -3
  76. data/lib/zernio-sdk/models/{attach_campaign_assets_request_structured_snippets_inner.rb → google_structured_snippet.rb} +3 -3
  77. data/lib/zernio-sdk/models/list_account_callouts200_response.rb +2 -2
  78. data/lib/zernio-sdk/models/list_account_callouts200_response_callouts_inner.rb +13 -14
  79. data/lib/zernio-sdk/models/list_account_sitelinks200_response.rb +179 -0
  80. data/lib/zernio-sdk/models/list_account_sitelinks200_response_sitelinks_inner.rb +210 -0
  81. data/lib/zernio-sdk/models/list_account_structured_snippets200_response.rb +179 -0
  82. data/lib/zernio-sdk/models/list_account_structured_snippets200_response_structured_snippets_inner.rb +194 -0
  83. data/lib/zernio-sdk/models/list_ad_group_assets200_response.rb +201 -0
  84. data/lib/zernio-sdk/models/list_ad_group_assets200_response_callouts_inner.rb +165 -0
  85. data/lib/zernio-sdk/models/list_ad_group_assets200_response_sitelinks_inner.rb +192 -0
  86. data/lib/zernio-sdk/models/list_ad_group_assets200_response_structured_snippets_inner.rb +176 -0
  87. data/lib/zernio-sdk/models/list_campaign_assets200_response.rb +201 -0
  88. data/lib/zernio-sdk/models/list_campaign_assets200_response_callouts_inner.rb +165 -0
  89. data/lib/zernio-sdk/models/list_campaign_assets200_response_sitelinks_inner.rb +192 -0
  90. data/lib/zernio-sdk/models/list_campaign_assets200_response_structured_snippets_inner.rb +176 -0
  91. data/lib/zernio-sdk/models/remove_account_callout_request.rb +45 -3
  92. data/lib/zernio-sdk/models/remove_ad_group_assets_request.rb +281 -0
  93. data/lib/zernio-sdk/models/remove_campaign_assets200_response.rb +147 -0
  94. data/lib/zernio-sdk/models/remove_campaign_assets_request.rb +281 -0
  95. data/lib/zernio-sdk/models/update_account_callouts200_response.rb +156 -0
  96. data/lib/zernio-sdk/models/update_account_callouts_request.rb +253 -0
  97. data/lib/zernio-sdk/models/update_account_callouts_request_updates_inner.rb +186 -0
  98. data/lib/zernio-sdk/models/update_account_callouts_request_updates_inner_callout_asset.rb +182 -0
  99. data/lib/zernio-sdk/models/update_account_sitelinks_request.rb +253 -0
  100. data/lib/zernio-sdk/models/update_account_sitelinks_request_updates_inner.rb +216 -0
  101. data/lib/zernio-sdk/models/update_account_sitelinks_request_updates_inner_sitelink_asset.rb +241 -0
  102. data/lib/zernio-sdk/models/update_account_structured_snippets_request.rb +253 -0
  103. data/lib/zernio-sdk/models/update_account_structured_snippets_request_updates_inner.rb +186 -0
  104. data/lib/zernio-sdk/models/update_ad_request.rb +112 -1
  105. data/lib/zernio-sdk/models/update_campaign_assets200_response.rb +147 -0
  106. data/lib/zernio-sdk/models/update_campaign_assets_request.rb +253 -0
  107. data/lib/zernio-sdk/models/webhook_payload_post_platform.rb +1 -1
  108. data/lib/zernio-sdk/version.rb +1 -1
  109. data/lib/zernio-sdk.rb +40 -2
  110. data/openapi.yaml +2027 -329
  111. data/spec/api/ad_accounts_api_spec.rb +118 -8
  112. data/spec/api/ad_campaigns_api_spec.rb +98 -5
  113. data/spec/models/ad_creative_spec.rb +18 -0
  114. data/spec/models/add_account_sitelinks201_response_sitelinks_inner_spec.rb +60 -0
  115. data/spec/models/add_account_sitelinks201_response_spec.rb +42 -0
  116. data/spec/models/add_account_sitelinks_request_spec.rb +48 -0
  117. data/spec/models/add_account_structured_snippets201_response_spec.rb +42 -0
  118. data/spec/models/add_account_structured_snippets201_response_structured_snippets_inner_spec.rb +52 -0
  119. data/spec/models/add_account_structured_snippets_request_spec.rb +48 -0
  120. data/spec/models/attach_ad_group_assets201_response_spec.rb +54 -0
  121. data/spec/models/create_standalone_ad_request_additional_descriptions_inner_spec.rb +32 -0
  122. data/spec/models/create_standalone_ad_request_additional_headlines_inner_spec.rb +32 -0
  123. data/spec/models/get_ad200_response_spec.rb +12 -0
  124. data/spec/models/google_asset_update_spec.rb +60 -0
  125. data/spec/models/google_rsa_description_spec.rb +46 -0
  126. data/spec/models/google_rsa_headline_spec.rb +46 -0
  127. data/spec/models/{attach_campaign_assets_request_sitelinks_inner_spec.rb → google_sitelink_spec.rb} +6 -6
  128. data/spec/models/{attach_campaign_assets_request_structured_snippets_inner_spec.rb → google_structured_snippet_spec.rb} +6 -6
  129. data/spec/models/list_account_callouts200_response_callouts_inner_spec.rb +2 -2
  130. data/spec/models/list_account_sitelinks200_response_sitelinks_inner_spec.rb +78 -0
  131. data/spec/models/list_account_sitelinks200_response_spec.rb +54 -0
  132. data/spec/models/list_account_structured_snippets200_response_spec.rb +54 -0
  133. data/spec/models/list_account_structured_snippets200_response_structured_snippets_inner_spec.rb +66 -0
  134. data/spec/models/list_ad_group_assets200_response_callouts_inner_spec.rb +48 -0
  135. data/spec/models/list_ad_group_assets200_response_sitelinks_inner_spec.rb +66 -0
  136. data/spec/models/list_ad_group_assets200_response_spec.rb +66 -0
  137. data/spec/models/list_ad_group_assets200_response_structured_snippets_inner_spec.rb +54 -0
  138. data/spec/models/list_campaign_assets200_response_callouts_inner_spec.rb +48 -0
  139. data/spec/models/list_campaign_assets200_response_sitelinks_inner_spec.rb +66 -0
  140. data/spec/models/list_campaign_assets200_response_spec.rb +66 -0
  141. data/spec/models/list_campaign_assets200_response_structured_snippets_inner_spec.rb +54 -0
  142. data/spec/models/remove_ad_group_assets_request_spec.rb +54 -0
  143. data/spec/models/remove_campaign_assets200_response_spec.rb +36 -0
  144. data/spec/models/remove_campaign_assets_request_spec.rb +54 -0
  145. data/spec/models/update_account_callouts200_response_spec.rb +42 -0
  146. data/spec/models/update_account_callouts_request_spec.rb +48 -0
  147. data/spec/models/update_account_callouts_request_updates_inner_callout_asset_spec.rb +36 -0
  148. data/spec/models/update_account_callouts_request_updates_inner_spec.rb +42 -0
  149. data/spec/models/update_account_sitelinks_request_spec.rb +48 -0
  150. data/spec/models/update_account_sitelinks_request_updates_inner_sitelink_asset_spec.rb +54 -0
  151. data/spec/models/update_account_sitelinks_request_updates_inner_spec.rb +48 -0
  152. data/spec/models/update_account_structured_snippets_request_spec.rb +48 -0
  153. data/spec/models/update_account_structured_snippets_request_updates_inner_spec.rb +42 -0
  154. data/spec/models/update_ad_request_spec.rb +18 -0
  155. data/spec/models/update_campaign_assets200_response_spec.rb +36 -0
  156. data/spec/models/update_campaign_assets_request_spec.rb +48 -0
  157. data/zernio-sdk-0.0.902.gem +0 -0
  158. metadata +163 -11
  159. data/zernio-sdk-0.0.900.gem +0 -0
data/openapi.yaml CHANGED
@@ -148,13 +148,13 @@ x-documentation:
148
148
  Receive real-time notifications for post status changes, account events, and incoming messages:
149
149
 
150
150
  - `post.scheduled` - Post entered the scheduled state: created with a schedule, added to a queue, a draft promoted to scheduled or queued, a failed post retried, or a recycled clone created
151
- - `post.published` - Post successfully published
152
- - `post.failed` - Post failed on all platforms
153
- - `post.partial` - Post published to some platforms, failed on others
151
+ - `post.published` - Post successfully published. If a platform target later fails background reconciliation, the post is re-rolled up and a `post.failed` or `post.partial` follows for the same post.
152
+ - `post.failed` - Post failed on all platforms. Can follow an earlier `post.published` for the same post when background reconciliation discovers the publish never actually completed.
153
+ - `post.partial` - Post published to some platforms, failed on others. Can follow an earlier `post.published` for the same post when background reconciliation discovers one target's publish never actually completed.
154
154
  - `post.cancelled` - Post publishing was cancelled
155
155
  - `post.recycled` - Post recycled (cloned and re-scheduled)
156
- - `post.platform.published` - A single platform target inside a post finished publishing successfully. Fires once per platform-account as it terminates, without waiting for other platforms on the same post. Use this for incremental UIs; use `post.published` for the post-level rollup.
157
- - `post.platform.failed` - A single platform target inside a post failed permanently. Temporary/retryable failures do NOT fire this event, only permanent ones, so retry loops stay quiet.
156
+ - `post.platform.published` - A single platform target inside a post finished publishing successfully. Fires once per platform-account as it terminates, without waiting for other platforms on the same post. Use this for incremental UIs; use `post.published` for the post-level rollup. A target that later fails background reconciliation (e.g. a Facebook video Meta accepted but never actually published) emits `post.platform.failed` afterward for the same target.
157
+ - `post.platform.failed` - A single platform target inside a post failed permanently. Temporary/retryable failures do NOT fire this event, only permanent ones, so retry loops stay quiet. Can fire after this same target already emitted `post.platform.published`, when background reconciliation later discovers the publish never actually completed on the platform's side.
158
158
  - `post.platform.deleted` - A single platform target inside a post was detected as deleted on the platform after publishing (e.g. the user deleted the Instagram post natively). Detection is poll-driven via Zernio background sync (~hourly), not real-time. `platform.deletedAt` carries the detection time. Coverage is bounded to the posts the platform listing returns.
159
159
  - `post.tiktok.url_resolved` - A published TikTok post's public URL became available. TikTok exposes the numeric video id asynchronously, so `post.published` / `post.platform.published` can carry an empty `publishedUrl` for TikTok; this event delivers the URL once resolved (at most once per platform target). Never fires for drafts or private posts, which have no public URL.
160
160
  - `post.external.created` - A native post authored outside Zernio (e.g. a Google Business Profile localPost created in the Google UI) was detected by our sync for the first time. Poll-driven (~hourly), not real-time. Payload carries `post.source: "external"`.
@@ -2724,8 +2724,11 @@ components:
2724
2724
  and for `post.tiktok.url_resolved` (same shape, fired when a
2725
2725
  published TikTok post's public URL is backfilled). Terminal events
2726
2726
  fire once per platform target inside a post as that platform
2727
- reaches a terminal state (published or permanent failure). The
2728
- `post` envelope mirrors the shape of `WebhookPayloadPost` so
2727
+ reaches a terminal state (published or permanent failure), except
2728
+ that a target which later fails background reconciliation emits
2729
+ `post.platform.failed` a second time, after its own
2730
+ `post.platform.published`. The `post` envelope mirrors the shape
2731
+ of `WebhookPayloadPost` so
2729
2732
  consumers can reuse rendering logic; the `platform` block
2730
2733
  identifies which specific platform transitioned; the `account`
2731
2734
  block identifies the connected account behind that
@@ -9175,6 +9178,135 @@ components:
9175
9178
  enum: [applied, not_returned, unavailable]
9176
9179
  description: 'Meta creative readback result. applied means Meta returned promotion metadata; not_returned means the read succeeded without promotion metadata; unavailable means the read failed. Only applied confirms the returned offer. Missing metadata is not proof that Ads Manager displays the requested Promotion.'
9177
9180
  example: not_returned
9181
+ GoogleSitelink:
9182
+ type: object
9183
+ required:
9184
+ - text
9185
+ - linkUrl
9186
+ properties:
9187
+ text:
9188
+ type: string
9189
+ minLength: 1
9190
+ maxLength: 25
9191
+ linkUrl:
9192
+ type: string
9193
+ format: uri
9194
+ description1:
9195
+ type: string
9196
+ minLength: 1
9197
+ maxLength: 35
9198
+ description2:
9199
+ type: string
9200
+ minLength: 1
9201
+ maxLength: 35
9202
+ GoogleStructuredSnippet:
9203
+ type: object
9204
+ required:
9205
+ - header
9206
+ - values
9207
+ properties:
9208
+ header:
9209
+ type: string
9210
+ enum:
9211
+ - Amenities
9212
+ - Brands
9213
+ - Courses
9214
+ - Degree programs
9215
+ - Destinations
9216
+ - Featured hotels
9217
+ - Insurance coverage
9218
+ - Models
9219
+ - Neighborhoods
9220
+ - Service catalog
9221
+ - Shows
9222
+ - Styles
9223
+ - Types
9224
+ values:
9225
+ type: array
9226
+ minItems: 3
9227
+ maxItems: 10
9228
+ items:
9229
+ type: string
9230
+ minLength: 1
9231
+ maxLength: 25
9232
+ GoogleAssetUpdate:
9233
+ type: object
9234
+ required:
9235
+ - assetResourceName
9236
+ properties:
9237
+ assetResourceName:
9238
+ type: string
9239
+ pattern: ^customers/\d+/assets/\d+$
9240
+ description: "Asset resource name returned by a list operation. Must belong to the selected customer."
9241
+ sitelinkAsset:
9242
+ type: object
9243
+ properties:
9244
+ linkText:
9245
+ type: string
9246
+ minLength: 1
9247
+ maxLength: 25
9248
+ description1:
9249
+ type: string
9250
+ maxLength: 35
9251
+ description2:
9252
+ type: string
9253
+ maxLength: 35
9254
+ linkUrl:
9255
+ type: string
9256
+ format: uri
9257
+ description: "Alias for finalUrls with one URL. Do not supply both."
9258
+ minProperties: 1
9259
+ finalUrls:
9260
+ type: array
9261
+ items:
9262
+ type: string
9263
+ format: uri
9264
+ minItems: 1
9265
+ calloutAsset:
9266
+ type: object
9267
+ required:
9268
+ - calloutText
9269
+ properties:
9270
+ calloutText:
9271
+ type: string
9272
+ minLength: 1
9273
+ maxLength: 25
9274
+ structuredSnippetAsset:
9275
+ $ref: '#/components/schemas/GoogleStructuredSnippet'
9276
+ description: "Supply fields for exactly one asset type per update. finalUrls may accompany sitelinkAsset. Shared asset edits affect every attachment using the asset."
9277
+
9278
+ GoogleRsaHeadline:
9279
+ type: object
9280
+ required:
9281
+ - text
9282
+ properties:
9283
+ text:
9284
+ type: string
9285
+ minLength: 1
9286
+ maxLength: 30
9287
+ pinnedField:
9288
+ type: string
9289
+ enum:
9290
+ - HEADLINE_1
9291
+ - HEADLINE_2
9292
+ - HEADLINE_3
9293
+ description: "Optional fixed headline position. Omit to leave the asset unpinned."
9294
+ GoogleRsaDescription:
9295
+ type: object
9296
+ required:
9297
+ - text
9298
+ properties:
9299
+ text:
9300
+ type: string
9301
+ minLength: 1
9302
+ maxLength: 90
9303
+ pinnedField:
9304
+ type: string
9305
+ enum:
9306
+ - DESCRIPTION_1
9307
+ - DESCRIPTION_2
9308
+ description: "Optional fixed description position. Omit to leave the asset unpinned."
9309
+
9178
9310
  Ad:
9179
9311
  type: object
9180
9312
  properties:
@@ -9331,6 +9463,27 @@ components:
9331
9463
  type: [object, "null"]
9332
9464
  description: Platform-specific creative data. Fields vary by platform.
9333
9465
  properties:
9466
+ headlines:
9467
+ type: array
9468
+ minItems: 3
9469
+ maxItems: 15
9470
+ items:
9471
+ $ref: '#/components/schemas/GoogleRsaHeadline'
9472
+ description: "Google RSA only. Replaces the complete headline list. No padding or truncation on update."
9473
+ descriptions:
9474
+ type: array
9475
+ minItems: 2
9476
+ maxItems: 4
9477
+ items:
9478
+ $ref: '#/components/schemas/GoogleRsaDescription'
9479
+ description: "Google RSA only. Replaces the complete description list. No padding or truncation on update."
9480
+ finalUrls:
9481
+ type: array
9482
+ minItems: 1
9483
+ items:
9484
+ type: string
9485
+ format: uri
9486
+ description: "Google RSA only. Replaces final URLs. Omitted lists stay unchanged."
9334
9487
  thumbnailUrl: { type: [string, "null"], description: Primary thumbnail/image URL }
9335
9488
  imageUrl: { type: string, description: Alternative image URL }
9336
9489
  videoId: { type: [string, "null"], description: "Meta video ID for VIDEO-type ads. Null for non-video ads. Callers that need an embeddable MP4 can call GET /{videoId}?fields=source with the page access token." }
@@ -10365,7 +10518,10 @@ webhooks:
10365
10518
  consumers building incremental UIs get notified immediately, even
10366
10519
  when other platforms on the same post are still processing.
10367
10520
  The envelope event (`post.published` / `post.partial`) fires
10368
- separately AFTER all platforms have terminated.
10521
+ separately AFTER all platforms have terminated. A target that later
10522
+ fails background reconciliation (e.g. a Facebook video Meta accepted
10523
+ but never actually published) emits `post.platform.failed` for the
10524
+ same target afterward.
10369
10525
  tags: [Webhook Events]
10370
10526
  requestBody:
10371
10527
  required: true
@@ -10385,7 +10541,9 @@ webhooks:
10385
10541
  permanently. Temporary/retryable failures do NOT fire this event,
10386
10542
  only permanent ones do, so retry loops stay quiet. The envelope event
10387
10543
  (`post.failed` / `post.partial`) fires separately AFTER all
10388
- platforms have terminated.
10544
+ platforms have terminated. Can also fire a second time for a target
10545
+ that already emitted `post.platform.published`, if background
10546
+ reconciliation later discovers the publish never actually completed.
10389
10547
  tags: [Webhook Events]
10390
10548
  requestBody:
10391
10549
  required: true
@@ -44491,6 +44649,11 @@ paths:
44491
44649
  summary: Get ad details
44492
44650
  description: |
44493
44651
  Returns an ad with its creative, targeting, status, and performance metrics.
44652
+ Google Search ads include current creative.headlines, creative.descriptions and creative.finalUrls,
44653
+ preserving pinnedField. Top-level cachedAt and stale report cache freshness. Google mutations invalidate this read.
44654
+ RSA enrichment requires a stored advertisingChannelType of SEARCH. Ads with an unknown or other channel
44655
+ return their stored details without a Google read. If RSA enrichment fails, the stored ad is returned
44656
+ with HTTP 200 and without cache metadata.
44494
44657
 
44495
44658
  The `{adId}` path segment accepts any identifier dialect Zernio indexes for the ad:
44496
44659
  - the Zernio internal `_id` (24-char hex)
@@ -44523,10 +44686,26 @@ paths:
44523
44686
  description: Ad details
44524
44687
  content:
44525
44688
  application/json:
44689
+ example:
44690
+ ad:
44691
+ platform: google
44692
+ creative:
44693
+ headlines:
44694
+ - { text: "Social Media API", pinnedField: HEADLINE_1 }
44695
+ - { text: "Schedule Your Posts" }
44696
+ - { text: "Build With Zernio" }
44697
+ descriptions:
44698
+ - { text: "Connect social accounts with one API.", pinnedField: DESCRIPTION_1 }
44699
+ - { text: "Build social publishing into your application." }
44700
+ finalUrls: ["https://zernio.com"]
44701
+ cachedAt: null
44702
+ stale: false
44526
44703
  schema:
44527
44704
  type: object
44528
44705
  properties:
44529
44706
  ad: { $ref: '#/components/schemas/Ad' }
44707
+ cachedAt: { type: [string, "null"], format: date-time, description: "Google RSA details cache timestamp." }
44708
+ stale: { type: boolean, description: "Whether Google RSA details use the last successful cached response." }
44530
44709
  '400': { $ref: '#/components/responses/BadRequest' }
44531
44710
  '401': { $ref: '#/components/responses/Unauthorized' }
44532
44711
  '404': { $ref: '#/components/responses/NotFound' }
@@ -44549,7 +44728,11 @@ paths:
44549
44728
  Each list you send becomes the FULL new set of its kind (criteria not in the
44550
44729
  list are removed); a kind left out is untouched. Any other `targeting` field
44551
44730
  returns 400: Google cannot mutate broad targeting post-create without recreating
44552
- the campaign. `creative` returns 501.
44731
+ the campaign. RSA text updates use top-level `headlines`, `descriptions` and `finalUrls`.
44732
+ Each supplied array replaces the full list; omit a field to preserve it. Use 3-15 headlines
44733
+ (1-30 characters) and 2-4 descriptions (1-90 characters). Omit an asset to remove it;
44734
+ omit pinnedField on an included asset to unpin it. Updates do not pad or truncate text.
44735
+ The legacy creative fields remain unsupported for Google.
44553
44736
  - **LinkedIn**: status, budget, targeting (countries or regions, excludedLocations (countries),
44554
44737
  the B2B facets, and audience segments; applied to the LinkedIn Campaign via
44555
44738
  PARTIAL_UPDATE, and REPLACES the campaign's entire targetingCriteria, not a merge),
@@ -44592,9 +44775,51 @@ paths:
44592
44775
  required: true
44593
44776
  content:
44594
44777
  application/json:
44778
+ examples:
44779
+ googleRsa:
44780
+ summary: "Replace and pin Google RSA text."
44781
+ value:
44782
+ headlines:
44783
+ - text: Social Media API
44784
+ pinnedField: HEADLINE_1
44785
+ - text: Schedule Your Posts
44786
+ - text: Build With Zernio
44787
+ descriptions:
44788
+ - text: Connect social accounts and schedule posts with the Zernio API.
44789
+ pinnedField: DESCRIPTION_1
44790
+ - text: Build social publishing into your application.
44791
+ finalUrls:
44792
+ - https://zernio.com
44793
+ metaPromotion:
44794
+ summary: "Remove a Meta promotion."
44795
+ value:
44796
+ creative:
44797
+ promotion: null
44798
+ creativeFeatures: { auto_promotion_tag: OPT_OUT }
44595
44799
  schema:
44596
44800
  type: object
44597
44801
  properties:
44802
+ headlines:
44803
+ type: array
44804
+ minItems: 3
44805
+ maxItems: 15
44806
+ items:
44807
+ $ref: '#/components/schemas/GoogleRsaHeadline'
44808
+ description: "Google RSA only. Replaces the complete headline list. No padding or truncation on update."
44809
+ descriptions:
44810
+ type: array
44811
+ minItems: 2
44812
+ maxItems: 4
44813
+ items:
44814
+ $ref: '#/components/schemas/GoogleRsaDescription'
44815
+ description: "Google RSA only. Replaces the complete description list. No padding or truncation on update."
44816
+ finalUrls:
44817
+ type: array
44818
+ minItems: 1
44819
+ items:
44820
+ type: string
44821
+ format: uri
44822
+ description: "Google RSA only. Replaces final URLs. Omitted lists stay unchanged."
44598
44823
  status: { type: string, enum: [active, paused] }
44599
44824
  budget:
44600
44825
  type: object
@@ -44702,10 +44927,6 @@ paths:
44702
44927
  videoId: { type: string, description: "Meta only. Reuse an already-uploaded ad video (from POST /v1/ads/videos or GET /v1/ads/videos) instead of re-uploading via videoUrl." }
44703
44928
  existingCreativeId: { type: string, description: "Meta only. Repoint the ad at an existing library creative (from GET /v1/ads/creatives); all other creative fields are ignored." }
44704
44929
  name: { type: string, maxLength: 255, description: "Rename the ad. Now propagated to Meta (POST /{ad-id}); non-Meta platforms return 501." }
44705
- example:
44706
- creative:
44707
- promotion: null
44708
- creativeFeatures: { auto_promotion_tag: OPT_OUT }
44709
44930
  responses:
44710
44931
  '200':
44711
44932
  description: Ad updated
@@ -44796,322 +45017,977 @@ paths:
44796
45017
  '404': { description: Ad not found }
44797
45018
 
44798
45019
  /v1/ads/campaigns/{campaignId}/assets:
45020
+ get:
45021
+ operationId: listCampaignAssets
45022
+ summary: List campaign assets
45023
+ x-resource-group: ads
45024
+ tags:
45025
+ - Ad Campaigns
45026
+ x-platforms:
45027
+ - google
45028
+ description: "Lists directly attached Google assets. Fresh reads are cached for 10 minutes; exhausted quota\
45029
+ \ may return the last successful read with stale=true. Inherited assets are not included."
45030
+ security:
45031
+ - bearerAuth: []
45032
+ parameters:
45033
+ - name: campaignId
45034
+ in: path
45035
+ required: true
45036
+ schema:
45037
+ type: string
45038
+ pattern: ^\d+$
45039
+ description: "Numeric Google platform id."
45040
+ - name: accountId
45041
+ in: query
45042
+ required: true
45043
+ schema:
45044
+ type: string
45045
+ pattern: ^[a-fA-F0-9]{24}$
45046
+ description: "Zernio Google Ads connection id."
45047
+ - name: customerId
45048
+ in: query
45049
+ schema:
45050
+ type: string
45051
+ pattern: ^\d+$
45052
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
45053
+ responses:
45054
+ '200':
45055
+ description: "Assets returned."
45056
+ content:
45057
+ application/json:
45058
+ schema:
45059
+ type: object
45060
+ properties:
45061
+ campaignId:
45062
+ type: string
45063
+ sitelinks:
45064
+ type: array
45065
+ items:
45066
+ type: object
45067
+ properties:
45068
+ assetResourceName:
45069
+ type: string
45070
+ campaignAssetResourceName:
45071
+ type: string
45072
+ text:
45073
+ type: string
45074
+ linkUrl:
45075
+ type: string
45076
+ format: uri
45077
+ description1:
45078
+ type: string
45079
+ description2:
45080
+ type: string
45081
+ callouts:
45082
+ type: array
45083
+ items:
45084
+ type: object
45085
+ properties:
45086
+ assetResourceName:
45087
+ type: string
45088
+ campaignAssetResourceName:
45089
+ type: string
45090
+ calloutText:
45091
+ type: string
45092
+ structuredSnippets:
45093
+ type: array
45094
+ items:
45095
+ type: object
45096
+ properties:
45097
+ assetResourceName:
45098
+ type: string
45099
+ campaignAssetResourceName:
45100
+ type: string
45101
+ header:
45102
+ type: string
45103
+ values:
45104
+ type: array
45105
+ items:
45106
+ type: string
45107
+ cachedAt:
45108
+ type:
45109
+ - string
45110
+ - 'null'
45111
+ format: date-time
45112
+ description: "Time of the cached Google read. Null when no cache was used."
45113
+ stale:
45114
+ type: boolean
45115
+ description: "True when exhausted quota required returning the last successful read."
45116
+ '400':
45117
+ $ref: '#/components/responses/BadRequest'
45118
+ '401':
45119
+ $ref: '#/components/responses/Unauthorized'
45120
+ '403':
45121
+ description: "Ads access is required."
45122
+ '404':
45123
+ $ref: '#/components/responses/NotFound'
45124
+ '429':
45125
+ description: "Google Ads operations budget or platform quota exhausted."
45126
+ '501':
45127
+ description: "Only supported on Google Ads."
44799
45128
  post:
44800
- x-resource-group: "ads"
44801
45129
  operationId: attachCampaignAssets
44802
- tags: ["Ad Campaigns"]
44803
- x-platforms: ["google"]
44804
- summary: Attach extension assets to a Google Search campaign
44805
- description: |-
44806
- Attach sitelinks, callouts and/or structured snippets to an already-existing Google
44807
- Search campaign. These are the same builders POST /v1/ads/create uses, but without rebuilding
44808
- the hierarchy. At least one of sitelinks, callouts or structuredSnippets is required.
44809
-
44810
- Google-only. Other platforms have no equivalent extension surface and return 501.
44811
-
44812
- Approval status is Google-async; poll `asset.policy_summary` after review. Assets
44813
- stay in the account library even if the campaign is later deleted.
45130
+ summary: Attach campaign assets
45131
+ x-resource-group: ads
45132
+ tags:
45133
+ - Ad Campaigns
45134
+ x-platforms:
45135
+ - google
45136
+ description: "Creates and attaches sitelinks, callouts and structured snippets in one Google mutation."
44814
45137
  security:
44815
- - bearerAuth: []
45138
+ - bearerAuth: []
44816
45139
  parameters:
44817
- - { name: campaignId, in: path, required: true, schema: { type: string }, description: "Numeric Google platform campaign id." }
45140
+ - name: campaignId
45141
+ in: path
45142
+ required: true
45143
+ schema:
45144
+ type: string
45145
+ pattern: ^\d+$
45146
+ description: "Numeric Google platform id."
44818
45147
  requestBody:
44819
45148
  required: true
44820
45149
  content:
44821
45150
  application/json:
44822
45151
  schema:
44823
45152
  type: object
44824
- required: [accountId]
45153
+ required:
45154
+ - accountId
44825
45155
  properties:
44826
- accountId: { type: string, description: "Zernio Google Ads SocialAccount id. Resolves the customer id + refresh token." }
44827
- customerId: { type: string, description: "Numeric Google Ads customer id. Required when the connection has multiple Google Ads accounts; optional (and inferred) when it has only one." }
45156
+ accountId:
45157
+ type: string
45158
+ pattern: ^[a-fA-F0-9]{24}$
45159
+ description: "Zernio Google Ads connection id."
45160
+ customerId:
45161
+ type: string
45162
+ pattern: ^\d+$
45163
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
44828
45164
  sitelinks:
44829
45165
  type: array
45166
+ items:
45167
+ $ref: '#/components/schemas/GoogleSitelink'
44830
45168
  minItems: 2
44831
45169
  maxItems: 20
44832
- description: "See POST /v1/ads/create sitelinks, same shape."
44833
- items:
44834
- type: object
44835
- required: [text, linkUrl]
44836
- properties:
44837
- text: { type: string, minLength: 1, maxLength: 25 }
44838
- linkUrl: { type: string, format: uri }
44839
- description1: { type: string, minLength: 1, maxLength: 35 }
44840
- description2: { type: string, minLength: 1, maxLength: 35 }
44841
45170
  callouts:
44842
45171
  type: array
45172
+ items:
45173
+ type: string
45174
+ minLength: 1
45175
+ maxLength: 25
44843
45176
  minItems: 1
44844
45177
  maxItems: 20
44845
- items: { type: string, minLength: 1, maxLength: 25 }
44846
45178
  structuredSnippets:
44847
45179
  type: array
45180
+ items:
45181
+ $ref: '#/components/schemas/GoogleStructuredSnippet'
44848
45182
  minItems: 1
44849
45183
  maxItems: 20
44850
- items:
44851
- type: object
44852
- required: [header, values]
44853
- properties:
44854
- header:
44855
- type: string
44856
- enum: [Amenities, Brands, Courses, Degree programs, Destinations, Featured hotels, Insurance coverage, Models, Neighborhoods, Service catalog, Shows, Styles, Types]
44857
- values:
44858
- type: array
44859
- minItems: 3
44860
- maxItems: 10
44861
- items: { type: string, minLength: 1, maxLength: 25 }
45184
+ description: "Provide at least one of sitelinks, callouts or structuredSnippets. Sitelink description1\
45185
+ \ and description2 must be supplied together."
45186
+ example:
45187
+ accountId: 64b1f0c8a1b2c3d4e5f60718
45188
+ customerId: '1234567890'
45189
+ sitelinks:
45190
+ - text: Pricing
45191
+ linkUrl: https://zernio.com/pricing
45192
+ - text: Documentation
45193
+ linkUrl: https://zernio.com/docs
45194
+ callouts:
45195
+ - Fast setup
45196
+ structuredSnippets:
45197
+ - header: Types
45198
+ values:
45199
+ - Scheduling
45200
+ - Analytics
45201
+ - Messaging
44862
45202
  responses:
44863
45203
  '201':
44864
- description: Assets attached
45204
+ description: "Assets created and attached."
44865
45205
  content:
44866
45206
  application/json:
44867
45207
  schema:
44868
45208
  type: object
44869
45209
  properties:
44870
- campaignId: { type: string }
44871
- sitelinkAssetResourceNames: { type: array, items: { type: string } }
44872
- calloutAssetResourceNames: { type: array, items: { type: string } }
44873
- structuredSnippetAssetResourceNames: { type: array, items: { type: string } }
44874
- '400': { description: "Invalid input, Google rejected the assets, an unknown customerId (not one of this connection's Google Ads accounts), or a required customerId missing when the connection has multiple Google Ads accounts" }
44875
- '401': { $ref: '#/components/responses/Unauthorized' }
45210
+ campaignId:
45211
+ type: string
45212
+ sitelinkAssetResourceNames:
45213
+ type: array
45214
+ items:
45215
+ type: string
45216
+ calloutAssetResourceNames:
45217
+ type: array
45218
+ items:
45219
+ type: string
45220
+ structuredSnippetAssetResourceNames:
45221
+ type: array
45222
+ items:
45223
+ type: string
45224
+ '400':
45225
+ $ref: '#/components/responses/BadRequest'
45226
+ '401':
45227
+ $ref: '#/components/responses/Unauthorized'
44876
45228
  '403':
44877
- description: 'Returned with code `ads_allowance_exceeded` when the team has no payment method on file and has reached the 500 free live ads: add a card to resume.'
44878
- '422': { description: "No Google Ads customer accounts on this connection. Reconnect Google Ads." }
44879
- '501': { description: Only supported on Google Ads }
44880
-
44881
- /v1/ads/campaigns/{campaignId}/analytics:
44882
- get:
44883
- x-resource-group: "ads"
44884
- operationId: getCampaignAnalytics
44885
- tags: ["Ad Insights"]
44886
- x-platforms: ["meta", "google", "tiktok", "linkedin", "pinterest", "x"]
44887
- summary: Get campaign analytics
44888
- description: |
44889
- Returns performance analytics for a whole campaign in one call: summary metrics, a daily
44890
- timeline over the requested date range (summed across the campaign's ads), and optional
44891
- demographic breakdowns. Breakdowns are fetched live from Meta at the campaign level (one call
44892
- per dimension, no per-ad fan-out), so an agency dashboard gets campaign-level age/gender/etc.
44893
- without summing thousands of per-ad reads. `campaignId` is the platform campaign id; pass
44894
- `platform` when a campaign id could be ambiguous across platforms. If no date range is provided,
44895
- defaults to the last 90 days. Date range is capped at 730 days max.
44896
- Google adds searchImpressionShare, searchBudgetLostImpressionShare,
44897
- searchRankLostImpressionShare, searchTopImpressionShare and searchAbsoluteTopImpressionShare
44898
- under analytics.summary for the requested inclusive range. These ratios are queried
44899
- together without daily segmentation and cached for 10 minutes. Unavailable values are
44900
- null. analytics.impressionShareCache reports cachedAt and stale independently of synced metrics.
45229
+ description: "Ads access is required."
45230
+ '404':
45231
+ $ref: '#/components/responses/NotFound'
45232
+ '429':
45233
+ description: "Google Ads operations budget or platform quota exhausted."
45234
+ '501':
45235
+ description: "Only supported on Google Ads."
45236
+ put:
45237
+ operationId: updateCampaignAssets
45238
+ summary: Update campaign assets
45239
+ x-resource-group: ads
45240
+ tags:
45241
+ - Ad Campaigns
45242
+ x-platforms:
45243
+ - google
45244
+ description: "Edits existing Google assets in place. Send updates with assetResourceName and the fields to change.\
45245
+ \ An asset is shared: changes affect every attachment using it. Omitted fields stay unchanged. The operation\
45246
+ \ consumes the Google operations budget and invalidates affected cached lists."
44901
45247
  security:
44902
- - bearerAuth: []
45248
+ - bearerAuth: []
44903
45249
  parameters:
44904
- - { name: campaignId, in: path, required: true, schema: { type: string }, description: "Platform campaign id (platformCampaignId)." }
44905
- - { name: platform, in: query, schema: { type: string }, description: "Disambiguate when the campaign id exists across platforms (e.g. facebook, instagram)." }
44906
- - { name: fromDate, in: query, schema: { type: string, format: date }, description: "Start of date range (YYYY-MM-DD). Defaults to 90 days ago." }
44907
- - { name: toDate, in: query, schema: { type: string, format: date }, description: "End of date range (YYYY-MM-DD). Defaults to today. Max 730-day range." }
44908
- - name: breakdowns
44909
- in: query
44910
- schema: { type: string }
44911
- description: |
44912
- Comma-separated breakdown dimensions.
44913
-
44914
- **Meta**: age, gender, country, publisher_platform, device_platform, region,
44915
- platform_position, impression_device, video_asset, image_asset, body_asset, title_asset.
44916
-
44917
- **LinkedIn** (firmographics): job_title, job_function, seniority, industry,
44918
- company, company_size, country, region. Rows carry the raw pivot `value`
44919
- plus a resolved `name`. LinkedIn serves these aggregated over the whole
44920
- range, delays the data 12-24h, and omits segments with fewer than 3 events.
45250
+ - name: campaignId
45251
+ in: path
45252
+ required: true
45253
+ schema:
45254
+ type: string
45255
+ pattern: ^\d+$
45256
+ description: "Numeric Google platform id."
45257
+ requestBody:
45258
+ required: true
45259
+ content:
45260
+ application/json:
45261
+ schema:
45262
+ type: object
45263
+ required:
45264
+ - accountId
45265
+ - updates
45266
+ properties:
45267
+ accountId:
45268
+ type: string
45269
+ pattern: ^[a-fA-F0-9]{24}$
45270
+ description: "Zernio Google Ads connection id."
45271
+ customerId:
45272
+ type: string
45273
+ pattern: ^\d+$
45274
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
45275
+ updates:
45276
+ type: array
45277
+ items:
45278
+ $ref: '#/components/schemas/GoogleAssetUpdate'
45279
+ minItems: 1
45280
+ maxItems: 20
45281
+ example:
45282
+ accountId: 64b1f0c8a1b2c3d4e5f60718
45283
+ customerId: '1234567890'
45284
+ updates:
45285
+ - assetResourceName: customers/1234567890/assets/123
45286
+ calloutAsset:
45287
+ calloutText: Simple integration
44921
45288
  responses:
44922
45289
  '200':
44923
- description: Campaign analytics
44924
- content:
44925
- application/json:
44926
- schema: { $ref: '#/components/schemas/CampaignAnalyticsResponse' }
44927
- example:
44928
- campaign: { id: "123456789", platform: google }
44929
- analytics:
44930
- summary:
44931
- searchImpressionShare: 0.42
44932
- searchBudgetLostImpressionShare: 0.13
44933
- searchRankLostImpressionShare: 0.45
44934
- searchTopImpressionShare: 0.31
44935
- searchAbsoluteTopImpressionShare: null
44936
- impressionShareCache: { cachedAt: "2026-09-09T10:00:00Z", stale: false }
44937
- daily: []
44938
- '202':
44939
- description: Historical data is incomplete and backfill remains pending.
44940
- headers:
44941
- Retry-After:
44942
- $ref: '#/components/headers/BackfillRetryAfter'
45290
+ description: "Assets returned."
44943
45291
  content:
44944
45292
  application/json:
44945
45293
  schema:
44946
- allOf:
44947
- - { $ref: '#/components/schemas/CampaignAnalyticsResponse' }
44948
- - type: object
44949
- required: [backfillPending]
44950
- properties:
44951
- backfillPending: { type: boolean, description: 'Always true on this response. Part of the requested range is still being backfilled; retry until the request returns 200.' }
45294
+ type: object
45295
+ properties:
45296
+ updated:
45297
+ type: integer
44952
45298
  '400':
44953
- description: "Invalid parameter (e.g. an unknown `breakdowns` dimension). The message lists the offending value(s) and the supported set."
44954
- content:
44955
- application/json:
44956
- schema: { $ref: '#/components/schemas/ErrorResponse' }
44957
- '401': { $ref: '#/components/responses/Unauthorized' }
45299
+ $ref: '#/components/responses/BadRequest'
45300
+ '401':
45301
+ $ref: '#/components/responses/Unauthorized'
44958
45302
  '403':
44959
- description: Ads access required. Legacy plans need the Ads add-on; included by default on usage-based plans.
44960
- '404': { $ref: '#/components/responses/NotFound' }
44961
- '429': { description: "Google operations budget or quota exhausted without a cached impression-share result." }
44962
-
44963
- /v1/ads/preview:
44964
- post:
44965
- x-resource-group: "ads"
44966
- operationId: generateAdPreviews
44967
- tags: ["Ad Creatives"]
44968
- x-platforms: ["meta"]
44969
- summary: Render pre-create ad previews
44970
- description: |
44971
- Renders how a creative would look per placement BEFORE any ad exists, via Meta's
44972
- `/generatepreviews`. Provide exactly one creative source: `existingCreativeId` or `creativeSpec`.
44973
- Each preview is an HTML `<iframe>` snippet embeddable directly. Unknown `formats` values
44974
- return Meta's 400 verbatim.
45303
+ description: "Ads access is required."
45304
+ '404':
45305
+ $ref: '#/components/responses/NotFound'
45306
+ '429':
45307
+ description: "Google Ads operations budget or platform quota exhausted."
45308
+ '501':
45309
+ description: "Only supported on Google Ads."
45310
+ delete:
45311
+ operationId: removeCampaignAssets
45312
+ summary: Remove campaign assets
45313
+ x-resource-group: ads
45314
+ tags:
45315
+ - Ad Campaigns
45316
+ x-platforms:
45317
+ - google
45318
+ description: "Removes the specified attachments only. Google assets cannot be deleted. Other attachments remain. assetResourceNames is retained for compatibility."
44975
45319
  security:
44976
- - bearerAuth: []
45320
+ - bearerAuth: []
45321
+ parameters:
45322
+ - name: campaignId
45323
+ in: path
45324
+ required: true
45325
+ schema:
45326
+ type: string
45327
+ pattern: ^\d+$
45328
+ description: "Numeric Google platform id."
44977
45329
  requestBody:
44978
45330
  required: true
44979
45331
  content:
44980
45332
  application/json:
44981
45333
  schema:
44982
45334
  type: object
44983
- required: [accountId, adAccountId]
45335
+ required:
45336
+ - accountId
45337
+ - assetResourceNames
45338
+ - campaignAssetResourceNames
44984
45339
  properties:
44985
- accountId: { type: string, description: "Zernio SocialAccount id used to resolve the Meta token." }
44986
- adAccountId: { type: string, description: "Platform ad account id (Meta act_<n>, Google customer id, LinkedIn account id, ...)." }
44987
- formats:
45340
+ accountId:
45341
+ type: string
45342
+ pattern: ^[a-fA-F0-9]{24}$
45343
+ description: "Zernio Google Ads connection id."
45344
+ customerId:
45345
+ type: string
45346
+ pattern: ^\d+$
45347
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
45348
+ assetResourceNames:
44988
45349
  type: array
45350
+ items:
45351
+ type: string
44989
45352
  minItems: 1
44990
- maxItems: 10
44991
- items: { type: string }
44992
- description: "Meta ad_format values, one preview per format. Defaults to [DESKTOP_FEED_STANDARD]."
44993
- existingCreativeId: { type: string, description: "Preview an existing ad-account creative by id. Mutually exclusive with creativeSpec." }
44994
- creativeSpec:
44995
- type: object
44996
- additionalProperties: true
44997
- description: "Raw Meta creative spec forwarded verbatim to /generatepreviews. Mutually exclusive with existingCreativeId."
45353
+ campaignAssetResourceNames:
45354
+ type: array
45355
+ items:
45356
+ type: string
45357
+ minItems: 1
45358
+ example:
45359
+ accountId: 64b1f0c8a1b2c3d4e5f60718
45360
+ customerId: '1234567890'
45361
+ assetResourceNames:
45362
+ - customers/1234567890/assets/123
45363
+ campaignAssetResourceNames:
45364
+ - customers/1234567890/campaignAssets/456~123~CALLOUT
44998
45365
  responses:
44999
45366
  '200':
45000
- description: Rendered previews
45367
+ description: "Assets returned."
45001
45368
  content:
45002
45369
  application/json:
45003
45370
  schema:
45004
45371
  type: object
45005
45372
  properties:
45006
- previews:
45007
- type: array
45008
- items:
45009
- type: object
45010
- properties:
45011
- format: { type: string }
45012
- html: { type: [string, "null"], description: "Meta's <iframe> snippet; null when Meta returned no preview for the format." }
45013
- '400': { description: "Invalid input, or Meta rejected the creative spec / ad_format; the message carries Meta's error" }
45014
- '401': { $ref: '#/components/responses/Unauthorized' }
45015
- '429': { description: Meta rate limit reached }
45016
- '501': { description: Only supported on Meta (facebook/instagram) }
45373
+ removed:
45374
+ type: boolean
45375
+ '400':
45376
+ $ref: '#/components/responses/BadRequest'
45377
+ '401':
45378
+ $ref: '#/components/responses/Unauthorized'
45379
+ '403':
45380
+ description: "Ads access is required."
45381
+ '404':
45382
+ $ref: '#/components/responses/NotFound'
45383
+ '429':
45384
+ description: "Google Ads operations budget or platform quota exhausted."
45385
+ '501':
45386
+ description: "Only supported on Google Ads."
45017
45387
 
45018
- /v1/ads/{adId}/preview:
45388
+ /v1/ads/ad-sets/{adSetId}/assets:
45019
45389
  get:
45020
- x-resource-group: "ads"
45021
- operationId: getAdPreviews
45022
- tags: ["Ad Creatives"]
45023
- x-platforms: ["meta"]
45024
- summary: Render previews of an existing ad
45025
- description: |
45026
- Renders an EXISTING ad per placement via Meta's `/{ad_id}/previews`. Each preview is an HTML
45027
- `<iframe>` snippet embeddable directly. Unknown `formats` values return Meta's 400 verbatim.
45390
+ operationId: listAdGroupAssets
45391
+ summary: List ad-group assets
45392
+ x-resource-group: ads
45393
+ tags:
45394
+ - Ad Campaigns
45395
+ x-platforms:
45396
+ - google
45397
+ description: "Lists directly attached Google assets. Fresh reads are cached for 10 minutes; exhausted quota\
45398
+ \ may return the last successful read with stale=true. Inherited assets are not included."
45028
45399
  security:
45029
- - bearerAuth: []
45400
+ - bearerAuth: []
45030
45401
  parameters:
45031
- - { name: adId, in: path, required: true, schema: { type: string }, description: "Zernio ad id (24-char hex)." }
45032
- - { name: formats, in: query, schema: { type: string }, description: "Comma-separated Meta ad_format values (max 10), one preview per format. Defaults to DESKTOP_FEED_STANDARD." }
45402
+ - name: adSetId
45403
+ in: path
45404
+ required: true
45405
+ schema:
45406
+ type: string
45407
+ pattern: ^\d+$
45408
+ description: "Numeric Google platform id."
45409
+ - name: accountId
45410
+ in: query
45411
+ required: true
45412
+ schema:
45413
+ type: string
45414
+ pattern: ^[a-fA-F0-9]{24}$
45415
+ description: "Zernio Google Ads connection id."
45416
+ - name: customerId
45417
+ in: query
45418
+ schema:
45419
+ type: string
45420
+ pattern: ^\d+$
45421
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
45033
45422
  responses:
45034
45423
  '200':
45035
- description: Rendered previews
45424
+ description: "Assets returned."
45036
45425
  content:
45037
45426
  application/json:
45038
45427
  schema:
45039
45428
  type: object
45040
45429
  properties:
45041
- adId: { type: string }
45042
- previews:
45430
+ adGroupId:
45431
+ type: string
45432
+ sitelinks:
45043
45433
  type: array
45044
45434
  items:
45045
45435
  type: object
45046
45436
  properties:
45047
- format: { type: string }
45048
- html: { type: [string, "null"], description: "Meta's <iframe> snippet; null when Meta returned no preview for the format." }
45049
- '400': { description: "Invalid input, or Meta rejected the ad_format; the message carries Meta's error" }
45050
- '401': { $ref: '#/components/responses/Unauthorized' }
45051
- '404': { description: Ad not found }
45052
- '429': { description: Meta rate limit reached }
45053
- '501': { description: Only supported on Meta (facebook/instagram) }
45054
-
45055
- /v1/ads/{adId}/media:
45056
- get:
45057
- x-resource-group: "ads"
45058
- operationId: getAdMedia
45059
- tags: ["Ad Creatives"]
45060
- x-platforms: ["meta"]
45061
- summary: Direct video and image URLs for an ad
45062
- description: |-
45063
- Returns the direct signed URLs for every video and image asset used by an ad's live
45064
- creative, normalised across shapes: single image/video, carousel,
45065
- Reels/Story (`object_story_spec.video_data`) and dynamic
45066
- creative (`asset_feed_spec`). Video items include Meta's poster thumbnail and the
45067
- video's Meta id when available.
45068
-
45069
- Reads Meta live rather than the stored creative blob because Meta's signed fbcdn
45070
- URLs carry an `oe=<hex>` expiration (image_url ~24 h, video source ~12 d). Treat
45071
- URLs as short-lived: re-fetch this endpoint before serving or downloading assets
45072
- instead of caching URLs beyond that window.
45073
- security:
45074
- - bearerAuth: []
45075
- parameters:
45076
- - { name: adId, in: path, required: true, schema: { type: string }, description: "Zernio ad id (24-char hex) or platform ad id." }
45077
- responses:
45078
- '200':
45079
- description: Media assets
45080
- content:
45081
- application/json:
45082
- schema:
45083
- type: object
45084
- properties:
45085
- adId: { type: string }
45086
- platform: { type: string, description: "'facebook' or 'instagram'. Only Meta is supported for now." }
45087
- media:
45437
+ assetResourceName:
45438
+ type: string
45439
+ adGroupAssetResourceName:
45440
+ type: string
45441
+ text:
45442
+ type: string
45443
+ linkUrl:
45444
+ type: string
45445
+ format: uri
45446
+ description1:
45447
+ type: string
45448
+ description2:
45449
+ type: string
45450
+ callouts:
45088
45451
  type: array
45089
45452
  items:
45090
45453
  type: object
45091
45454
  properties:
45092
- type: { type: string, enum: [image, video] }
45093
- url: { type: string, description: "Direct file URL (signed; short-lived, see description)." }
45094
- thumbnailUrl: { type: string, description: "Video poster URL (videos only)." }
45095
- videoId: { type: string, description: "Meta video id (videos only), reusable as video.id on the create endpoints." }
45096
- length: { type: number, description: "Video length in seconds (videos only)." }
45097
- index: { type: integer, description: "0-based position for carousel children or asset_feed_spec entries." }
45098
- '400': { description: "Invalid input" }
45099
- '401': { $ref: '#/components/responses/Unauthorized' }
45100
- '404': { description: Ad not found }
45101
- '422': { description: No active Meta connection for this ad. Reconnect the account. }
45102
- '501': { description: Only supported on Meta (facebook/instagram) }
45103
-
45104
- /v1/ads/keywords/ideas:
45455
+ assetResourceName:
45456
+ type: string
45457
+ adGroupAssetResourceName:
45458
+ type: string
45459
+ calloutText:
45460
+ type: string
45461
+ structuredSnippets:
45462
+ type: array
45463
+ items:
45464
+ type: object
45465
+ properties:
45466
+ assetResourceName:
45467
+ type: string
45468
+ adGroupAssetResourceName:
45469
+ type: string
45470
+ header:
45471
+ type: string
45472
+ values:
45473
+ type: array
45474
+ items:
45475
+ type: string
45476
+ cachedAt:
45477
+ type:
45478
+ - string
45479
+ - 'null'
45480
+ format: date-time
45481
+ description: "Time of the cached Google read. Null when no cache was used."
45482
+ stale:
45483
+ type: boolean
45484
+ description: "True when exhausted quota required returning the last successful read."
45485
+ '400':
45486
+ $ref: '#/components/responses/BadRequest'
45487
+ '401':
45488
+ $ref: '#/components/responses/Unauthorized'
45489
+ '403':
45490
+ description: "Ads access is required."
45491
+ '404':
45492
+ $ref: '#/components/responses/NotFound'
45493
+ '429':
45494
+ description: "Google Ads operations budget or platform quota exhausted."
45495
+ '501':
45496
+ description: "Only supported on Google Ads."
45105
45497
  post:
45106
- x-resource-group: "ads"
45107
- operationId: generateKeywordIdeas
45108
- tags: ["Ad Insights"]
45109
- x-platforms: ["google"]
45110
- summary: Generate keyword ideas (Google Keyword Planner)
45111
- description: |
45112
- Google Ads only. Runs Keyword Planner's generateKeywordIdeas from seed keywords, a seed URL,
45113
- or both, returning idea rows verbatim (avgMonthlySearches, competition, competitionIndex,
45114
- top-of-page bid micros, monthlySearchVolumes). Counters are int64s encoded as strings; bid
45498
+ operationId: attachAdGroupAssets
45499
+ summary: Attach ad-group assets
45500
+ x-resource-group: ads
45501
+ tags:
45502
+ - Ad Campaigns
45503
+ x-platforms:
45504
+ - google
45505
+ description: "Creates and attaches sitelinks, callouts and structured snippets in one Google mutation."
45506
+ security:
45507
+ - bearerAuth: []
45508
+ parameters:
45509
+ - name: adSetId
45510
+ in: path
45511
+ required: true
45512
+ schema:
45513
+ type: string
45514
+ pattern: ^\d+$
45515
+ description: "Numeric Google platform id."
45516
+ requestBody:
45517
+ required: true
45518
+ content:
45519
+ application/json:
45520
+ schema:
45521
+ type: object
45522
+ required:
45523
+ - accountId
45524
+ properties:
45525
+ accountId:
45526
+ type: string
45527
+ pattern: ^[a-fA-F0-9]{24}$
45528
+ description: "Zernio Google Ads connection id."
45529
+ customerId:
45530
+ type: string
45531
+ pattern: ^\d+$
45532
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
45533
+ sitelinks:
45534
+ type: array
45535
+ items:
45536
+ $ref: '#/components/schemas/GoogleSitelink'
45537
+ minItems: 2
45538
+ maxItems: 20
45539
+ callouts:
45540
+ type: array
45541
+ items:
45542
+ type: string
45543
+ minLength: 1
45544
+ maxLength: 25
45545
+ minItems: 1
45546
+ maxItems: 20
45547
+ structuredSnippets:
45548
+ type: array
45549
+ items:
45550
+ $ref: '#/components/schemas/GoogleStructuredSnippet'
45551
+ minItems: 1
45552
+ maxItems: 20
45553
+ description: "Provide at least one of sitelinks, callouts or structuredSnippets. Sitelink description1\
45554
+ \ and description2 must be supplied together."
45555
+ example:
45556
+ accountId: 64b1f0c8a1b2c3d4e5f60718
45557
+ customerId: '1234567890'
45558
+ sitelinks:
45559
+ - text: Pricing
45560
+ linkUrl: https://zernio.com/pricing
45561
+ - text: Documentation
45562
+ linkUrl: https://zernio.com/docs
45563
+ callouts:
45564
+ - Fast setup
45565
+ structuredSnippets:
45566
+ - header: Types
45567
+ values:
45568
+ - Scheduling
45569
+ - Analytics
45570
+ - Messaging
45571
+ responses:
45572
+ '201':
45573
+ description: "Assets created and attached."
45574
+ content:
45575
+ application/json:
45576
+ schema:
45577
+ type: object
45578
+ properties:
45579
+ adGroupId:
45580
+ type: string
45581
+ sitelinkAssetResourceNames:
45582
+ type: array
45583
+ items:
45584
+ type: string
45585
+ calloutAssetResourceNames:
45586
+ type: array
45587
+ items:
45588
+ type: string
45589
+ structuredSnippetAssetResourceNames:
45590
+ type: array
45591
+ items:
45592
+ type: string
45593
+ '400':
45594
+ $ref: '#/components/responses/BadRequest'
45595
+ '401':
45596
+ $ref: '#/components/responses/Unauthorized'
45597
+ '403':
45598
+ description: "Ads access is required."
45599
+ '404':
45600
+ $ref: '#/components/responses/NotFound'
45601
+ '429':
45602
+ description: "Google Ads operations budget or platform quota exhausted."
45603
+ '501':
45604
+ description: "Only supported on Google Ads."
45605
+ put:
45606
+ operationId: updateAdGroupAssets
45607
+ summary: Update ad-group assets
45608
+ x-resource-group: ads
45609
+ tags:
45610
+ - Ad Campaigns
45611
+ x-platforms:
45612
+ - google
45613
+ description: "Edits existing Google assets in place. Send updates with assetResourceName and the fields to change.\
45614
+ \ An asset is shared: changes affect every attachment using it. Omitted fields stay unchanged. The operation\
45615
+ \ consumes the Google operations budget and invalidates affected cached lists."
45616
+ security:
45617
+ - bearerAuth: []
45618
+ parameters:
45619
+ - name: adSetId
45620
+ in: path
45621
+ required: true
45622
+ schema:
45623
+ type: string
45624
+ pattern: ^\d+$
45625
+ description: "Numeric Google platform id."
45626
+ requestBody:
45627
+ required: true
45628
+ content:
45629
+ application/json:
45630
+ schema:
45631
+ type: object
45632
+ required:
45633
+ - accountId
45634
+ - updates
45635
+ properties:
45636
+ accountId:
45637
+ type: string
45638
+ pattern: ^[a-fA-F0-9]{24}$
45639
+ description: "Zernio Google Ads connection id."
45640
+ customerId:
45641
+ type: string
45642
+ pattern: ^\d+$
45643
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
45644
+ updates:
45645
+ type: array
45646
+ items:
45647
+ $ref: '#/components/schemas/GoogleAssetUpdate'
45648
+ minItems: 1
45649
+ maxItems: 20
45650
+ example:
45651
+ accountId: 64b1f0c8a1b2c3d4e5f60718
45652
+ customerId: '1234567890'
45653
+ updates:
45654
+ - assetResourceName: customers/1234567890/assets/123
45655
+ calloutAsset:
45656
+ calloutText: Simple integration
45657
+ responses:
45658
+ '200':
45659
+ description: "Assets returned."
45660
+ content:
45661
+ application/json:
45662
+ schema:
45663
+ type: object
45664
+ properties:
45665
+ updated:
45666
+ type: integer
45667
+ '400':
45668
+ $ref: '#/components/responses/BadRequest'
45669
+ '401':
45670
+ $ref: '#/components/responses/Unauthorized'
45671
+ '403':
45672
+ description: "Ads access is required."
45673
+ '404':
45674
+ $ref: '#/components/responses/NotFound'
45675
+ '429':
45676
+ description: "Google Ads operations budget or platform quota exhausted."
45677
+ '501':
45678
+ description: "Only supported on Google Ads."
45679
+ delete:
45680
+ operationId: removeAdGroupAssets
45681
+ summary: Remove ad-group assets
45682
+ x-resource-group: ads
45683
+ tags:
45684
+ - Ad Campaigns
45685
+ x-platforms:
45686
+ - google
45687
+ description: "Removes the specified attachments only. Google assets cannot be deleted. Other attachments remain. assetResourceNames is retained for compatibility."
45688
+ security:
45689
+ - bearerAuth: []
45690
+ parameters:
45691
+ - name: adSetId
45692
+ in: path
45693
+ required: true
45694
+ schema:
45695
+ type: string
45696
+ pattern: ^\d+$
45697
+ description: "Numeric Google platform id."
45698
+ requestBody:
45699
+ required: true
45700
+ content:
45701
+ application/json:
45702
+ schema:
45703
+ type: object
45704
+ required:
45705
+ - accountId
45706
+ - assetResourceNames
45707
+ - adGroupAssetResourceNames
45708
+ properties:
45709
+ accountId:
45710
+ type: string
45711
+ pattern: ^[a-fA-F0-9]{24}$
45712
+ description: "Zernio Google Ads connection id."
45713
+ customerId:
45714
+ type: string
45715
+ pattern: ^\d+$
45716
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
45717
+ assetResourceNames:
45718
+ type: array
45719
+ items:
45720
+ type: string
45721
+ minItems: 1
45722
+ adGroupAssetResourceNames:
45723
+ type: array
45724
+ items:
45725
+ type: string
45726
+ minItems: 1
45727
+ example:
45728
+ accountId: 64b1f0c8a1b2c3d4e5f60718
45729
+ customerId: '1234567890'
45730
+ assetResourceNames:
45731
+ - customers/1234567890/assets/123
45732
+ adGroupAssetResourceNames:
45733
+ - customers/1234567890/adGroupAssets/456~123~CALLOUT
45734
+ responses:
45735
+ '200':
45736
+ description: "Assets returned."
45737
+ content:
45738
+ application/json:
45739
+ schema:
45740
+ type: object
45741
+ properties:
45742
+ removed:
45743
+ type: boolean
45744
+ '400':
45745
+ $ref: '#/components/responses/BadRequest'
45746
+ '401':
45747
+ $ref: '#/components/responses/Unauthorized'
45748
+ '403':
45749
+ description: "Ads access is required."
45750
+ '404':
45751
+ $ref: '#/components/responses/NotFound'
45752
+ '429':
45753
+ description: "Google Ads operations budget or platform quota exhausted."
45754
+ '501':
45755
+ description: "Only supported on Google Ads."
45756
+
45757
+ /v1/ads/campaigns/{campaignId}/analytics:
45758
+ get:
45759
+ x-resource-group: "ads"
45760
+ operationId: getCampaignAnalytics
45761
+ tags: ["Ad Insights"]
45762
+ x-platforms: ["meta", "google", "tiktok", "linkedin", "pinterest", "x"]
45763
+ summary: Get campaign analytics
45764
+ description: |
45765
+ Returns performance analytics for a whole campaign in one call: summary metrics, a daily
45766
+ timeline over the requested date range (summed across the campaign's ads), and optional
45767
+ demographic breakdowns. Breakdowns are fetched live from Meta at the campaign level (one call
45768
+ per dimension, no per-ad fan-out), so an agency dashboard gets campaign-level age/gender/etc.
45769
+ without summing thousands of per-ad reads. `campaignId` is the platform campaign id; pass
45770
+ `platform` when a campaign id could be ambiguous across platforms. If no date range is provided,
45771
+ defaults to the last 90 days. Date range is capped at 730 days max.
45772
+ Google adds searchImpressionShare, searchBudgetLostImpressionShare,
45773
+ searchRankLostImpressionShare, searchTopImpressionShare and searchAbsoluteTopImpressionShare
45774
+ under analytics.summary for the requested inclusive range. These ratios are queried
45775
+ together without daily segmentation and cached for 10 minutes. Unavailable values are
45776
+ null. analytics.impressionShareCache reports cachedAt and stale independently of synced metrics.
45777
+ security:
45778
+ - bearerAuth: []
45779
+ parameters:
45780
+ - { name: campaignId, in: path, required: true, schema: { type: string }, description: "Platform campaign id (platformCampaignId)." }
45781
+ - { name: platform, in: query, schema: { type: string }, description: "Disambiguate when the campaign id exists across platforms (e.g. facebook, instagram)." }
45782
+ - { name: fromDate, in: query, schema: { type: string, format: date }, description: "Start of date range (YYYY-MM-DD). Defaults to 90 days ago." }
45783
+ - { name: toDate, in: query, schema: { type: string, format: date }, description: "End of date range (YYYY-MM-DD). Defaults to today. Max 730-day range." }
45784
+ - name: breakdowns
45785
+ in: query
45786
+ schema: { type: string }
45787
+ description: |
45788
+ Comma-separated breakdown dimensions.
45789
+
45790
+ **Meta**: age, gender, country, publisher_platform, device_platform, region,
45791
+ platform_position, impression_device, video_asset, image_asset, body_asset, title_asset.
45792
+
45793
+ **LinkedIn** (firmographics): job_title, job_function, seniority, industry,
45794
+ company, company_size, country, region. Rows carry the raw pivot `value`
45795
+ plus a resolved `name`. LinkedIn serves these aggregated over the whole
45796
+ range, delays the data 12-24h, and omits segments with fewer than 3 events.
45797
+ responses:
45798
+ '200':
45799
+ description: Campaign analytics
45800
+ content:
45801
+ application/json:
45802
+ schema: { $ref: '#/components/schemas/CampaignAnalyticsResponse' }
45803
+ example:
45804
+ campaign: { id: "123456789", platform: google }
45805
+ analytics:
45806
+ summary:
45807
+ searchImpressionShare: 0.42
45808
+ searchBudgetLostImpressionShare: 0.13
45809
+ searchRankLostImpressionShare: 0.45
45810
+ searchTopImpressionShare: 0.31
45811
+ searchAbsoluteTopImpressionShare: null
45812
+ impressionShareCache: { cachedAt: "2026-09-09T10:00:00Z", stale: false }
45813
+ daily: []
45814
+ '202':
45815
+ description: Historical data is incomplete and backfill remains pending.
45816
+ headers:
45817
+ Retry-After:
45818
+ $ref: '#/components/headers/BackfillRetryAfter'
45819
+ content:
45820
+ application/json:
45821
+ schema:
45822
+ allOf:
45823
+ - { $ref: '#/components/schemas/CampaignAnalyticsResponse' }
45824
+ - type: object
45825
+ required: [backfillPending]
45826
+ properties:
45827
+ backfillPending: { type: boolean, description: 'Always true on this response. Part of the requested range is still being backfilled; retry until the request returns 200.' }
45828
+ '400':
45829
+ description: "Invalid parameter (e.g. an unknown `breakdowns` dimension). The message lists the offending value(s) and the supported set."
45830
+ content:
45831
+ application/json:
45832
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
45833
+ '401': { $ref: '#/components/responses/Unauthorized' }
45834
+ '403':
45835
+ description: Ads access required. Legacy plans need the Ads add-on; included by default on usage-based plans.
45836
+ '404': { $ref: '#/components/responses/NotFound' }
45837
+ '429': { description: "Google operations budget or quota exhausted without a cached impression-share result." }
45838
+
45839
+ /v1/ads/preview:
45840
+ post:
45841
+ x-resource-group: "ads"
45842
+ operationId: generateAdPreviews
45843
+ tags: ["Ad Creatives"]
45844
+ x-platforms: ["meta"]
45845
+ summary: Render pre-create ad previews
45846
+ description: |
45847
+ Renders how a creative would look per placement BEFORE any ad exists, via Meta's
45848
+ `/generatepreviews`. Provide exactly one creative source: `existingCreativeId` or `creativeSpec`.
45849
+ Each preview is an HTML `<iframe>` snippet embeddable directly. Unknown `formats` values
45850
+ return Meta's 400 verbatim.
45851
+ security:
45852
+ - bearerAuth: []
45853
+ requestBody:
45854
+ required: true
45855
+ content:
45856
+ application/json:
45857
+ schema:
45858
+ type: object
45859
+ required: [accountId, adAccountId]
45860
+ properties:
45861
+ accountId: { type: string, description: "Zernio SocialAccount id used to resolve the Meta token." }
45862
+ adAccountId: { type: string, description: "Platform ad account id (Meta act_<n>, Google customer id, LinkedIn account id, ...)." }
45863
+ formats:
45864
+ type: array
45865
+ minItems: 1
45866
+ maxItems: 10
45867
+ items: { type: string }
45868
+ description: "Meta ad_format values, one preview per format. Defaults to [DESKTOP_FEED_STANDARD]."
45869
+ existingCreativeId: { type: string, description: "Preview an existing ad-account creative by id. Mutually exclusive with creativeSpec." }
45870
+ creativeSpec:
45871
+ type: object
45872
+ additionalProperties: true
45873
+ description: "Raw Meta creative spec forwarded verbatim to /generatepreviews. Mutually exclusive with existingCreativeId."
45874
+ responses:
45875
+ '200':
45876
+ description: Rendered previews
45877
+ content:
45878
+ application/json:
45879
+ schema:
45880
+ type: object
45881
+ properties:
45882
+ previews:
45883
+ type: array
45884
+ items:
45885
+ type: object
45886
+ properties:
45887
+ format: { type: string }
45888
+ html: { type: [string, "null"], description: "Meta's <iframe> snippet; null when Meta returned no preview for the format." }
45889
+ '400': { description: "Invalid input, or Meta rejected the creative spec / ad_format; the message carries Meta's error" }
45890
+ '401': { $ref: '#/components/responses/Unauthorized' }
45891
+ '429': { description: Meta rate limit reached }
45892
+ '501': { description: Only supported on Meta (facebook/instagram) }
45893
+
45894
+ /v1/ads/{adId}/preview:
45895
+ get:
45896
+ x-resource-group: "ads"
45897
+ operationId: getAdPreviews
45898
+ tags: ["Ad Creatives"]
45899
+ x-platforms: ["meta"]
45900
+ summary: Render previews of an existing ad
45901
+ description: |
45902
+ Renders an EXISTING ad per placement via Meta's `/{ad_id}/previews`. Each preview is an HTML
45903
+ `<iframe>` snippet embeddable directly. Unknown `formats` values return Meta's 400 verbatim.
45904
+ security:
45905
+ - bearerAuth: []
45906
+ parameters:
45907
+ - { name: adId, in: path, required: true, schema: { type: string }, description: "Zernio ad id (24-char hex)." }
45908
+ - { name: formats, in: query, schema: { type: string }, description: "Comma-separated Meta ad_format values (max 10), one preview per format. Defaults to DESKTOP_FEED_STANDARD." }
45909
+ responses:
45910
+ '200':
45911
+ description: Rendered previews
45912
+ content:
45913
+ application/json:
45914
+ schema:
45915
+ type: object
45916
+ properties:
45917
+ adId: { type: string }
45918
+ previews:
45919
+ type: array
45920
+ items:
45921
+ type: object
45922
+ properties:
45923
+ format: { type: string }
45924
+ html: { type: [string, "null"], description: "Meta's <iframe> snippet; null when Meta returned no preview for the format." }
45925
+ '400': { description: "Invalid input, or Meta rejected the ad_format; the message carries Meta's error" }
45926
+ '401': { $ref: '#/components/responses/Unauthorized' }
45927
+ '404': { description: Ad not found }
45928
+ '429': { description: Meta rate limit reached }
45929
+ '501': { description: Only supported on Meta (facebook/instagram) }
45930
+
45931
+ /v1/ads/{adId}/media:
45932
+ get:
45933
+ x-resource-group: "ads"
45934
+ operationId: getAdMedia
45935
+ tags: ["Ad Creatives"]
45936
+ x-platforms: ["meta"]
45937
+ summary: Direct video and image URLs for an ad
45938
+ description: |-
45939
+ Returns the direct signed URLs for every video and image asset used by an ad's live
45940
+ creative, normalised across shapes: single image/video, carousel,
45941
+ Reels/Story (`object_story_spec.video_data`) and dynamic
45942
+ creative (`asset_feed_spec`). Video items include Meta's poster thumbnail and the
45943
+ video's Meta id when available.
45944
+
45945
+ Reads Meta live rather than the stored creative blob because Meta's signed fbcdn
45946
+ URLs carry an `oe=<hex>` expiration (image_url ~24 h, video source ~12 d). Treat
45947
+ URLs as short-lived: re-fetch this endpoint before serving or downloading assets
45948
+ instead of caching URLs beyond that window.
45949
+ security:
45950
+ - bearerAuth: []
45951
+ parameters:
45952
+ - { name: adId, in: path, required: true, schema: { type: string }, description: "Zernio ad id (24-char hex) or platform ad id." }
45953
+ responses:
45954
+ '200':
45955
+ description: Media assets
45956
+ content:
45957
+ application/json:
45958
+ schema:
45959
+ type: object
45960
+ properties:
45961
+ adId: { type: string }
45962
+ platform: { type: string, description: "'facebook' or 'instagram'. Only Meta is supported for now." }
45963
+ media:
45964
+ type: array
45965
+ items:
45966
+ type: object
45967
+ properties:
45968
+ type: { type: string, enum: [image, video] }
45969
+ url: { type: string, description: "Direct file URL (signed; short-lived, see description)." }
45970
+ thumbnailUrl: { type: string, description: "Video poster URL (videos only)." }
45971
+ videoId: { type: string, description: "Meta video id (videos only), reusable as video.id on the create endpoints." }
45972
+ length: { type: number, description: "Video length in seconds (videos only)." }
45973
+ index: { type: integer, description: "0-based position for carousel children or asset_feed_spec entries." }
45974
+ '400': { description: "Invalid input" }
45975
+ '401': { $ref: '#/components/responses/Unauthorized' }
45976
+ '404': { description: Ad not found }
45977
+ '422': { description: No active Meta connection for this ad. Reconnect the account. }
45978
+ '501': { description: Only supported on Meta (facebook/instagram) }
45979
+
45980
+ /v1/ads/keywords/ideas:
45981
+ post:
45982
+ x-resource-group: "ads"
45983
+ operationId: generateKeywordIdeas
45984
+ tags: ["Ad Insights"]
45985
+ x-platforms: ["google"]
45986
+ summary: Generate keyword ideas (Google Keyword Planner)
45987
+ description: |
45988
+ Google Ads only. Runs Keyword Planner's generateKeywordIdeas from seed keywords, a seed URL,
45989
+ or both, returning idea rows verbatim (avgMonthlySearches, competition, competitionIndex,
45990
+ top-of-page bid micros, monthlySearchVolumes). Counters are int64s encoded as strings; bid
45115
45991
  values are micros of the account currency. Omitting `countries` targets worldwide.
45116
45992
  security:
45117
45993
  - bearerAuth: []
@@ -47671,141 +48547,943 @@ paths:
47671
48547
 
47672
48548
  /v1/ads/accounts/callouts:
47673
48549
  get:
47674
- x-resource-group: "ads"
47675
48550
  operationId: listAccountCallouts
47676
- tags: ["Ad Accounts"]
47677
- x-platforms: ["google"]
47678
- summary: List account-level callout extensions
47679
- description: |-
47680
- Google Ads compliance row C.75: callout assets linked at the CUSTOMER
47681
- level via `customer_asset` (not a campaign or ad group), so they serve
47682
- fleet-wide across the account. Google only; every other platform
47683
- returns 501. Cached for the quota window (10 minutes fresh, up to 7
47684
- days last-good), and gated by the shared Google Ads operations budget
47685
- on a cache miss. The response carries `cachedAt` and `stale`, set when
47686
- a quota-exhausted call falls back to the last-good copy instead of a
47687
- live read.
48551
+ summary: List account callouts
48552
+ x-resource-group: ads
48553
+ tags:
48554
+ - Ad Accounts
48555
+ x-platforms:
48556
+ - google
48557
+ description: "Lists directly attached Google assets. Fresh reads are cached for 10 minutes; exhausted quota\
48558
+ \ may return the last successful read with stale=true. Inherited assets are not included. Preserves Google\
48559
+ \ RMF C.75 account-level callouts."
47688
48560
  security:
47689
- - bearerAuth: []
48561
+ - bearerAuth: []
47690
48562
  parameters:
47691
- - { name: accountId, in: query, required: true, schema: { type: string }, description: "Google ads SocialAccount id." }
47692
- - { name: customerId, in: query, schema: { type: string }, description: "Numeric Google Ads customer id (no dashes). Defaults to the account's connected customer." }
48563
+ - name: accountId
48564
+ in: query
48565
+ required: true
48566
+ schema:
48567
+ type: string
48568
+ pattern: ^[a-fA-F0-9]{24}$
48569
+ description: "Zernio Google Ads connection id."
48570
+ - name: customerId
48571
+ in: query
48572
+ schema:
48573
+ type: string
48574
+ pattern: ^\d+$
48575
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
47693
48576
  responses:
47694
48577
  '200':
47695
- description: Account-level callouts
48578
+ description: "Assets returned."
47696
48579
  content:
47697
48580
  application/json:
47698
48581
  schema:
47699
48582
  type: object
47700
48583
  properties:
47701
- customerId: { type: string }
48584
+ customerId:
48585
+ type: string
47702
48586
  callouts:
47703
48587
  type: array
47704
48588
  items:
47705
48589
  type: object
47706
48590
  properties:
47707
- assetId: { type: string }
47708
- text: { type: string }
47709
- status: { type: string, description: "customer_asset.status, e.g. ENABLED, REMOVED, PAUSED." }
47710
- cachedAt: { type: [string, "null"], format: date-time, description: "When this list was fetched from Google. Null when it was never served from cache." }
47711
- stale: { type: boolean, description: "True when Google's daily API quota was exhausted and this is the last successful fetch, not a live read." }
47712
- '400': { $ref: '#/components/responses/BadRequest' }
47713
- '401': { $ref: '#/components/responses/Unauthorized' }
48591
+ assetId:
48592
+ type: string
48593
+ status:
48594
+ type: string
48595
+ text:
48596
+ type: string
48597
+ cachedAt:
48598
+ type:
48599
+ - string
48600
+ - 'null'
48601
+ format: date-time
48602
+ description: "Time of the cached Google read. Null when no cache was used."
48603
+ stale:
48604
+ type: boolean
48605
+ description: "True when exhausted quota required returning the last successful read."
48606
+ '400':
48607
+ $ref: '#/components/responses/BadRequest'
48608
+ '401':
48609
+ $ref: '#/components/responses/Unauthorized'
47714
48610
  '403':
47715
- description: Ads access required (Ads add-on on legacy plans, included on usage-based plans).
47716
- '404': { $ref: '#/components/responses/NotFound' }
47717
- '429': { description: Google Ads operations budget exhausted; retry later }
47718
- '501': { description: Only available on Google Ads accounts }
47719
-
48611
+ description: "Ads access is required."
48612
+ '404':
48613
+ $ref: '#/components/responses/NotFound'
48614
+ '429':
48615
+ description: "Google Ads operations budget or platform quota exhausted."
48616
+ '501':
48617
+ description: "Only supported on Google Ads."
47720
48618
  post:
47721
- x-resource-group: "ads"
47722
48619
  operationId: addAccountCallouts
47723
- tags: ["Ad Accounts"]
47724
- x-platforms: ["google"]
47725
- summary: Add account-level callout extensions
47726
- description: |-
47727
- Creates one asset plus one `customerAsset` link (field type CALLOUT)
47728
- per callout text, in a single mutate. Google only; every other
47729
- platform returns 501.
48620
+ summary: Add account callouts
48621
+ x-resource-group: ads
48622
+ tags:
48623
+ - Ad Accounts
48624
+ x-platforms:
48625
+ - google
48626
+ description: "Creates assets and customer_asset links for this Google customer. Links apply at account level."
47730
48627
  security:
47731
- - bearerAuth: []
48628
+ - bearerAuth: []
47732
48629
  requestBody:
47733
48630
  required: true
47734
48631
  content:
47735
48632
  application/json:
47736
48633
  schema:
47737
48634
  type: object
47738
- required: [accountId, callouts]
48635
+ required:
48636
+ - accountId
48637
+ - callouts
47739
48638
  properties:
47740
- accountId: { type: string, description: "Zernio SocialAccount id owning the Google Ads connection." }
47741
- customerId: { type: string, description: "Numeric Google Ads customer id. Only required when the connection has more than one." }
48639
+ accountId:
48640
+ type: string
48641
+ pattern: ^[a-fA-F0-9]{24}$
48642
+ description: "Zernio Google Ads connection id."
48643
+ customerId:
48644
+ type: string
48645
+ pattern: ^\d+$
48646
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
47742
48647
  callouts:
47743
48648
  type: array
48649
+ items:
48650
+ type: string
48651
+ minLength: 1
48652
+ maxLength: 25
47744
48653
  minItems: 1
47745
48654
  maxItems: 20
47746
- items: { type: string, minLength: 1, maxLength: 25 }
47747
- description: 'Callout text, 1-25 characters each; up to 20 per request (Google''s CalloutAsset limits).'
48655
+ example:
48656
+ accountId: 64b1f0c8a1b2c3d4e5f60718
48657
+ customerId: '1234567890'
48658
+ callouts:
48659
+ - Fast setup
47748
48660
  responses:
47749
48661
  '201':
47750
- description: Callouts created
48662
+ description: "Assets created and attached."
47751
48663
  content:
47752
48664
  application/json:
47753
48665
  schema:
47754
48666
  type: object
47755
48667
  properties:
47756
- customerId: { type: string }
48668
+ customerId:
48669
+ type: string
47757
48670
  callouts:
47758
48671
  type: array
47759
48672
  items:
47760
48673
  type: object
47761
48674
  properties:
47762
- assetId: { type: string }
47763
- text: { type: string }
47764
- '400': { $ref: '#/components/responses/BadRequest' }
47765
- '401': { $ref: '#/components/responses/Unauthorized' }
48675
+ assetId:
48676
+ type: string
48677
+ text:
48678
+ type: string
48679
+ '400':
48680
+ $ref: '#/components/responses/BadRequest'
48681
+ '401':
48682
+ $ref: '#/components/responses/Unauthorized'
47766
48683
  '403':
47767
- description: Ads access required (Ads add-on on legacy plans, included on usage-based plans).
47768
- '404': { $ref: '#/components/responses/NotFound' }
47769
- '501': { description: Only supported on Google Ads }
47770
-
48684
+ description: "Ads access is required."
48685
+ '404':
48686
+ $ref: '#/components/responses/NotFound'
48687
+ '429':
48688
+ description: "Google Ads operations budget or platform quota exhausted."
48689
+ '501':
48690
+ description: "Only supported on Google Ads."
48691
+ put:
48692
+ operationId: updateAccountCallouts
48693
+ summary: Update account callouts
48694
+ x-resource-group: ads
48695
+ tags:
48696
+ - Ad Accounts
48697
+ x-platforms:
48698
+ - google
48699
+ description: "Edits existing Google assets in place. Send updates with assetResourceName and the fields to change.\
48700
+ \ An asset is shared: changes affect every attachment using it. Omitted fields stay unchanged. The operation\
48701
+ \ consumes the Google operations budget and invalidates affected cached lists."
48702
+ security:
48703
+ - bearerAuth: []
48704
+ requestBody:
48705
+ required: true
48706
+ content:
48707
+ application/json:
48708
+ schema:
48709
+ type: object
48710
+ required:
48711
+ - accountId
48712
+ - updates
48713
+ properties:
48714
+ accountId:
48715
+ type: string
48716
+ pattern: ^[a-fA-F0-9]{24}$
48717
+ description: "Zernio Google Ads connection id."
48718
+ customerId:
48719
+ type: string
48720
+ pattern: ^\d+$
48721
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
48722
+ updates:
48723
+ type: array
48724
+ items:
48725
+ type: object
48726
+ required:
48727
+ - assetResourceName
48728
+ properties:
48729
+ assetResourceName:
48730
+ type: string
48731
+ pattern: ^customers/\d+/assets/\d+$
48732
+ description: "Asset resource name returned by a list operation. Must belong to the selected\
48733
+ \ customer."
48734
+ calloutAsset:
48735
+ type: object
48736
+ required:
48737
+ - calloutText
48738
+ properties:
48739
+ calloutText:
48740
+ type: string
48741
+ minLength: 1
48742
+ maxLength: 25
48743
+ description: "Provide at least one field belonging to this asset type."
48744
+ minItems: 1
48745
+ maxItems: 20
48746
+ example:
48747
+ accountId: 64b1f0c8a1b2c3d4e5f60718
48748
+ customerId: '1234567890'
48749
+ updates:
48750
+ - assetResourceName: customers/1234567890/assets/123
48751
+ calloutAsset:
48752
+ calloutText: Simple integration
48753
+ responses:
48754
+ '200':
48755
+ description: "Assets returned."
48756
+ content:
48757
+ application/json:
48758
+ schema:
48759
+ type: object
48760
+ properties:
48761
+ updated:
48762
+ type: integer
48763
+ customerId:
48764
+ type: string
48765
+ '400':
48766
+ $ref: '#/components/responses/BadRequest'
48767
+ '401':
48768
+ $ref: '#/components/responses/Unauthorized'
48769
+ '403':
48770
+ description: "Ads access is required."
48771
+ '404':
48772
+ $ref: '#/components/responses/NotFound'
48773
+ '429':
48774
+ description: "Google Ads operations budget or platform quota exhausted."
48775
+ '501':
48776
+ description: "Only supported on Google Ads."
47771
48777
  delete:
47772
- x-resource-group: "ads"
47773
48778
  operationId: removeAccountCallout
47774
- tags: ["Ad Accounts"]
47775
- x-platforms: ["google"]
47776
- summary: Remove an account-level callout extension
47777
- description: |-
47778
- Removes the `customerAsset` link (`customers/{cid}/customerAssets/{assetId}~CALLOUT`).
47779
- Google only; every other platform returns 501.
48779
+ summary: Remove account callout
48780
+ x-resource-group: ads
48781
+ tags:
48782
+ - Ad Accounts
48783
+ x-platforms:
48784
+ - google
48785
+ description: "Removes the customer_asset attachment only. The underlying shared asset and its campaign or ad-group\
48786
+ \ attachments remain."
47780
48787
  security:
47781
- - bearerAuth: []
48788
+ - bearerAuth: []
47782
48789
  requestBody:
47783
48790
  required: true
47784
48791
  content:
47785
48792
  application/json:
47786
48793
  schema:
47787
48794
  type: object
47788
- required: [accountId, assetId]
48795
+ required:
48796
+ - accountId
48797
+ - assetId
47789
48798
  properties:
47790
- accountId: { type: string, description: "Zernio SocialAccount id owning the Google Ads connection." }
47791
- customerId: { type: string, description: "Numeric Google Ads customer id. Only required when the connection has more than one." }
47792
- assetId: { type: string, description: "Numeric asset id from GET /v1/ads/accounts/callouts." }
48799
+ accountId:
48800
+ type: string
48801
+ pattern: ^[a-fA-F0-9]{24}$
48802
+ description: "Zernio Google Ads connection id."
48803
+ customerId:
48804
+ type: string
48805
+ pattern: ^\d+$
48806
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
48807
+ assetId:
48808
+ type: string
48809
+ pattern: ^\d+$
48810
+ example:
48811
+ accountId: 64b1f0c8a1b2c3d4e5f60718
48812
+ customerId: '1234567890'
48813
+ assetId: '123'
47793
48814
  responses:
47794
48815
  '200':
47795
- description: Callout removed
48816
+ description: "Assets returned."
47796
48817
  content:
47797
48818
  application/json:
47798
48819
  schema:
47799
48820
  type: object
47800
48821
  properties:
47801
- removed: { type: boolean }
47802
- customerId: { type: string }
47803
- '400': { $ref: '#/components/responses/BadRequest' }
47804
- '401': { $ref: '#/components/responses/Unauthorized' }
48822
+ removed:
48823
+ type: boolean
48824
+ customerId:
48825
+ type: string
48826
+ '400':
48827
+ $ref: '#/components/responses/BadRequest'
48828
+ '401':
48829
+ $ref: '#/components/responses/Unauthorized'
47805
48830
  '403':
47806
- description: Ads access required (Ads add-on on legacy plans, included on usage-based plans).
47807
- '404': { $ref: '#/components/responses/NotFound' }
47808
- '501': { description: Only supported on Google Ads }
48831
+ description: "Ads access is required."
48832
+ '404':
48833
+ $ref: '#/components/responses/NotFound'
48834
+ '429':
48835
+ description: "Google Ads operations budget or platform quota exhausted."
48836
+ '501':
48837
+ description: "Only supported on Google Ads."
48838
+
48839
+ /v1/ads/accounts/sitelinks:
48840
+ get:
48841
+ operationId: listAccountSitelinks
48842
+ summary: List account sitelinks
48843
+ x-resource-group: ads
48844
+ tags:
48845
+ - Ad Accounts
48846
+ x-platforms:
48847
+ - google
48848
+ description: "Lists directly attached Google assets. Fresh reads are cached for 10 minutes; exhausted quota\
48849
+ \ may return the last successful read with stale=true. Inherited assets are not included."
48850
+ security:
48851
+ - bearerAuth: []
48852
+ parameters:
48853
+ - name: accountId
48854
+ in: query
48855
+ required: true
48856
+ schema:
48857
+ type: string
48858
+ pattern: ^[a-fA-F0-9]{24}$
48859
+ description: "Zernio Google Ads connection id."
48860
+ - name: customerId
48861
+ in: query
48862
+ schema:
48863
+ type: string
48864
+ pattern: ^\d+$
48865
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
48866
+ responses:
48867
+ '200':
48868
+ description: "Assets returned."
48869
+ content:
48870
+ application/json:
48871
+ schema:
48872
+ type: object
48873
+ properties:
48874
+ customerId:
48875
+ type: string
48876
+ sitelinks:
48877
+ type: array
48878
+ items:
48879
+ type: object
48880
+ properties:
48881
+ assetId:
48882
+ type: string
48883
+ status:
48884
+ type: string
48885
+ assetResourceName:
48886
+ type: string
48887
+ customerAssetResourceName:
48888
+ type: string
48889
+ text:
48890
+ type: string
48891
+ linkUrl:
48892
+ type: string
48893
+ format: uri
48894
+ description1:
48895
+ type: string
48896
+ description2:
48897
+ type: string
48898
+ cachedAt:
48899
+ type:
48900
+ - string
48901
+ - 'null'
48902
+ format: date-time
48903
+ description: "Time of the cached Google read. Null when no cache was used."
48904
+ stale:
48905
+ type: boolean
48906
+ description: "True when exhausted quota required returning the last successful read."
48907
+ '400':
48908
+ $ref: '#/components/responses/BadRequest'
48909
+ '401':
48910
+ $ref: '#/components/responses/Unauthorized'
48911
+ '403':
48912
+ description: "Ads access is required."
48913
+ '404':
48914
+ $ref: '#/components/responses/NotFound'
48915
+ '429':
48916
+ description: "Google Ads operations budget or platform quota exhausted."
48917
+ '501':
48918
+ description: "Only supported on Google Ads."
48919
+ post:
48920
+ operationId: addAccountSitelinks
48921
+ summary: Add account sitelinks
48922
+ x-resource-group: ads
48923
+ tags:
48924
+ - Ad Accounts
48925
+ x-platforms:
48926
+ - google
48927
+ description: "Creates assets and customer_asset links for this Google customer. Links apply at account level."
48928
+ security:
48929
+ - bearerAuth: []
48930
+ requestBody:
48931
+ required: true
48932
+ content:
48933
+ application/json:
48934
+ schema:
48935
+ type: object
48936
+ required:
48937
+ - accountId
48938
+ - sitelinks
48939
+ properties:
48940
+ accountId:
48941
+ type: string
48942
+ pattern: ^[a-fA-F0-9]{24}$
48943
+ description: "Zernio Google Ads connection id."
48944
+ customerId:
48945
+ type: string
48946
+ pattern: ^\d+$
48947
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
48948
+ sitelinks:
48949
+ type: array
48950
+ items:
48951
+ $ref: '#/components/schemas/GoogleSitelink'
48952
+ minItems: 1
48953
+ maxItems: 20
48954
+ example:
48955
+ accountId: 64b1f0c8a1b2c3d4e5f60718
48956
+ customerId: '1234567890'
48957
+ sitelinks:
48958
+ - text: Pricing
48959
+ linkUrl: https://zernio.com/pricing
48960
+ responses:
48961
+ '201':
48962
+ description: "Assets created and attached."
48963
+ content:
48964
+ application/json:
48965
+ schema:
48966
+ type: object
48967
+ properties:
48968
+ customerId:
48969
+ type: string
48970
+ sitelinks:
48971
+ type: array
48972
+ items:
48973
+ type: object
48974
+ properties:
48975
+ assetId:
48976
+ type: string
48977
+ text:
48978
+ type: string
48979
+ minLength: 1
48980
+ maxLength: 25
48981
+ linkUrl:
48982
+ type: string
48983
+ format: uri
48984
+ description1:
48985
+ type: string
48986
+ minLength: 1
48987
+ maxLength: 35
48988
+ description2:
48989
+ type: string
48990
+ minLength: 1
48991
+ maxLength: 35
48992
+ '400':
48993
+ $ref: '#/components/responses/BadRequest'
48994
+ '401':
48995
+ $ref: '#/components/responses/Unauthorized'
48996
+ '403':
48997
+ description: "Ads access is required."
48998
+ '404':
48999
+ $ref: '#/components/responses/NotFound'
49000
+ '429':
49001
+ description: "Google Ads operations budget or platform quota exhausted."
49002
+ '501':
49003
+ description: "Only supported on Google Ads."
49004
+ put:
49005
+ operationId: updateAccountSitelinks
49006
+ summary: Update account sitelinks
49007
+ x-resource-group: ads
49008
+ tags:
49009
+ - Ad Accounts
49010
+ x-platforms:
49011
+ - google
49012
+ description: "Edits existing Google assets in place. Send updates with assetResourceName and the fields to change.\
49013
+ \ An asset is shared: changes affect every attachment using it. Omitted fields stay unchanged. The operation\
49014
+ \ consumes the Google operations budget and invalidates affected cached lists."
49015
+ security:
49016
+ - bearerAuth: []
49017
+ requestBody:
49018
+ required: true
49019
+ content:
49020
+ application/json:
49021
+ schema:
49022
+ type: object
49023
+ required:
49024
+ - accountId
49025
+ - updates
49026
+ properties:
49027
+ accountId:
49028
+ type: string
49029
+ pattern: ^[a-fA-F0-9]{24}$
49030
+ description: "Zernio Google Ads connection id."
49031
+ customerId:
49032
+ type: string
49033
+ pattern: ^\d+$
49034
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
49035
+ updates:
49036
+ type: array
49037
+ items:
49038
+ type: object
49039
+ required:
49040
+ - assetResourceName
49041
+ properties:
49042
+ assetResourceName:
49043
+ type: string
49044
+ pattern: ^customers/\d+/assets/\d+$
49045
+ description: "Asset resource name returned by a list operation. Must belong to the selected\
49046
+ \ customer."
49047
+ sitelinkAsset:
49048
+ type: object
49049
+ properties:
49050
+ linkText:
49051
+ type: string
49052
+ minLength: 1
49053
+ maxLength: 25
49054
+ description1:
49055
+ type: string
49056
+ maxLength: 35
49057
+ description2:
49058
+ type: string
49059
+ maxLength: 35
49060
+ linkUrl:
49061
+ type: string
49062
+ format: uri
49063
+ description: "Alias for finalUrls with one URL. Do not supply both."
49064
+ minProperties: 1
49065
+ finalUrls:
49066
+ type: array
49067
+ items:
49068
+ type: string
49069
+ format: uri
49070
+ minItems: 1
49071
+ description: "Provide at least one field belonging to this asset type."
49072
+ minItems: 1
49073
+ maxItems: 20
49074
+ example:
49075
+ accountId: 64b1f0c8a1b2c3d4e5f60718
49076
+ customerId: '1234567890'
49077
+ updates:
49078
+ - assetResourceName: customers/1234567890/assets/123
49079
+ sitelinkAsset:
49080
+ linkText: Explore pricing
49081
+ finalUrls:
49082
+ - https://zernio.com/pricing
49083
+ responses:
49084
+ '200':
49085
+ description: "Assets returned."
49086
+ content:
49087
+ application/json:
49088
+ schema:
49089
+ type: object
49090
+ properties:
49091
+ updated:
49092
+ type: integer
49093
+ customerId:
49094
+ type: string
49095
+ '400':
49096
+ $ref: '#/components/responses/BadRequest'
49097
+ '401':
49098
+ $ref: '#/components/responses/Unauthorized'
49099
+ '403':
49100
+ description: "Ads access is required."
49101
+ '404':
49102
+ $ref: '#/components/responses/NotFound'
49103
+ '429':
49104
+ description: "Google Ads operations budget or platform quota exhausted."
49105
+ '501':
49106
+ description: "Only supported on Google Ads."
49107
+ delete:
49108
+ operationId: removeAccountSitelink
49109
+ summary: Remove account sitelink
49110
+ x-resource-group: ads
49111
+ tags:
49112
+ - Ad Accounts
49113
+ x-platforms:
49114
+ - google
49115
+ description: "Removes the customer_asset attachment only. The underlying shared asset and its campaign or ad-group\
49116
+ \ attachments remain."
49117
+ security:
49118
+ - bearerAuth: []
49119
+ requestBody:
49120
+ required: true
49121
+ content:
49122
+ application/json:
49123
+ schema:
49124
+ type: object
49125
+ required:
49126
+ - accountId
49127
+ - assetId
49128
+ properties:
49129
+ accountId:
49130
+ type: string
49131
+ pattern: ^[a-fA-F0-9]{24}$
49132
+ description: "Zernio Google Ads connection id."
49133
+ customerId:
49134
+ type: string
49135
+ pattern: ^\d+$
49136
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
49137
+ assetId:
49138
+ type: string
49139
+ pattern: ^\d+$
49140
+ example:
49141
+ accountId: 64b1f0c8a1b2c3d4e5f60718
49142
+ customerId: '1234567890'
49143
+ assetId: '123'
49144
+ responses:
49145
+ '200':
49146
+ description: "Assets returned."
49147
+ content:
49148
+ application/json:
49149
+ schema:
49150
+ type: object
49151
+ properties:
49152
+ removed:
49153
+ type: boolean
49154
+ customerId:
49155
+ type: string
49156
+ '400':
49157
+ $ref: '#/components/responses/BadRequest'
49158
+ '401':
49159
+ $ref: '#/components/responses/Unauthorized'
49160
+ '403':
49161
+ description: "Ads access is required."
49162
+ '404':
49163
+ $ref: '#/components/responses/NotFound'
49164
+ '429':
49165
+ description: "Google Ads operations budget or platform quota exhausted."
49166
+ '501':
49167
+ description: "Only supported on Google Ads."
49168
+
49169
+ /v1/ads/accounts/structured-snippets:
49170
+ get:
49171
+ operationId: listAccountStructuredSnippets
49172
+ summary: List account snippets
49173
+ x-resource-group: ads
49174
+ tags:
49175
+ - Ad Accounts
49176
+ x-platforms:
49177
+ - google
49178
+ description: "Lists directly attached Google assets. Fresh reads are cached for 10 minutes; exhausted quota\
49179
+ \ may return the last successful read with stale=true. Inherited assets are not included."
49180
+ security:
49181
+ - bearerAuth: []
49182
+ parameters:
49183
+ - name: accountId
49184
+ in: query
49185
+ required: true
49186
+ schema:
49187
+ type: string
49188
+ pattern: ^[a-fA-F0-9]{24}$
49189
+ description: "Zernio Google Ads connection id."
49190
+ - name: customerId
49191
+ in: query
49192
+ schema:
49193
+ type: string
49194
+ pattern: ^\d+$
49195
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
49196
+ responses:
49197
+ '200':
49198
+ description: "Assets returned."
49199
+ content:
49200
+ application/json:
49201
+ schema:
49202
+ type: object
49203
+ properties:
49204
+ customerId:
49205
+ type: string
49206
+ structuredSnippets:
49207
+ type: array
49208
+ items:
49209
+ type: object
49210
+ properties:
49211
+ assetId:
49212
+ type: string
49213
+ status:
49214
+ type: string
49215
+ assetResourceName:
49216
+ type: string
49217
+ customerAssetResourceName:
49218
+ type: string
49219
+ header:
49220
+ type: string
49221
+ values:
49222
+ type: array
49223
+ items:
49224
+ type: string
49225
+ cachedAt:
49226
+ type:
49227
+ - string
49228
+ - 'null'
49229
+ format: date-time
49230
+ description: "Time of the cached Google read. Null when no cache was used."
49231
+ stale:
49232
+ type: boolean
49233
+ description: "True when exhausted quota required returning the last successful read."
49234
+ '400':
49235
+ $ref: '#/components/responses/BadRequest'
49236
+ '401':
49237
+ $ref: '#/components/responses/Unauthorized'
49238
+ '403':
49239
+ description: "Ads access is required."
49240
+ '404':
49241
+ $ref: '#/components/responses/NotFound'
49242
+ '429':
49243
+ description: "Google Ads operations budget or platform quota exhausted."
49244
+ '501':
49245
+ description: "Only supported on Google Ads."
49246
+ post:
49247
+ operationId: addAccountStructuredSnippets
49248
+ summary: Add account snippets
49249
+ x-resource-group: ads
49250
+ tags:
49251
+ - Ad Accounts
49252
+ x-platforms:
49253
+ - google
49254
+ description: "Creates assets and customer_asset links for this Google customer. Links apply at account level."
49255
+ security:
49256
+ - bearerAuth: []
49257
+ requestBody:
49258
+ required: true
49259
+ content:
49260
+ application/json:
49261
+ schema:
49262
+ type: object
49263
+ required:
49264
+ - accountId
49265
+ - structuredSnippets
49266
+ properties:
49267
+ accountId:
49268
+ type: string
49269
+ pattern: ^[a-fA-F0-9]{24}$
49270
+ description: "Zernio Google Ads connection id."
49271
+ customerId:
49272
+ type: string
49273
+ pattern: ^\d+$
49274
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
49275
+ structuredSnippets:
49276
+ type: array
49277
+ items:
49278
+ $ref: '#/components/schemas/GoogleStructuredSnippet'
49279
+ minItems: 1
49280
+ maxItems: 20
49281
+ example:
49282
+ accountId: 64b1f0c8a1b2c3d4e5f60718
49283
+ customerId: '1234567890'
49284
+ structuredSnippets:
49285
+ - header: Types
49286
+ values:
49287
+ - Scheduling
49288
+ - Analytics
49289
+ - Messaging
49290
+ responses:
49291
+ '201':
49292
+ description: "Assets created and attached."
49293
+ content:
49294
+ application/json:
49295
+ schema:
49296
+ type: object
49297
+ properties:
49298
+ customerId:
49299
+ type: string
49300
+ structuredSnippets:
49301
+ type: array
49302
+ items:
49303
+ type: object
49304
+ properties:
49305
+ assetId:
49306
+ type: string
49307
+ header:
49308
+ type: string
49309
+ enum:
49310
+ - Amenities
49311
+ - Brands
49312
+ - Courses
49313
+ - Degree programs
49314
+ - Destinations
49315
+ - Featured hotels
49316
+ - Insurance coverage
49317
+ - Models
49318
+ - Neighborhoods
49319
+ - Service catalog
49320
+ - Shows
49321
+ - Styles
49322
+ - Types
49323
+ values:
49324
+ type: array
49325
+ minItems: 3
49326
+ maxItems: 10
49327
+ items:
49328
+ type: string
49329
+ minLength: 1
49330
+ maxLength: 25
49331
+ '400':
49332
+ $ref: '#/components/responses/BadRequest'
49333
+ '401':
49334
+ $ref: '#/components/responses/Unauthorized'
49335
+ '403':
49336
+ description: "Ads access is required."
49337
+ '404':
49338
+ $ref: '#/components/responses/NotFound'
49339
+ '429':
49340
+ description: "Google Ads operations budget or platform quota exhausted."
49341
+ '501':
49342
+ description: "Only supported on Google Ads."
49343
+ put:
49344
+ operationId: updateAccountStructuredSnippets
49345
+ summary: Update account snippets
49346
+ x-resource-group: ads
49347
+ tags:
49348
+ - Ad Accounts
49349
+ x-platforms:
49350
+ - google
49351
+ description: "Edits existing Google assets in place. Send updates with assetResourceName and the fields to change.\
49352
+ \ An asset is shared: changes affect every attachment using it. Omitted fields stay unchanged. The operation\
49353
+ \ consumes the Google operations budget and invalidates affected cached lists."
49354
+ security:
49355
+ - bearerAuth: []
49356
+ requestBody:
49357
+ required: true
49358
+ content:
49359
+ application/json:
49360
+ schema:
49361
+ type: object
49362
+ required:
49363
+ - accountId
49364
+ - updates
49365
+ properties:
49366
+ accountId:
49367
+ type: string
49368
+ pattern: ^[a-fA-F0-9]{24}$
49369
+ description: "Zernio Google Ads connection id."
49370
+ customerId:
49371
+ type: string
49372
+ pattern: ^\d+$
49373
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
49374
+ updates:
49375
+ type: array
49376
+ items:
49377
+ type: object
49378
+ required:
49379
+ - assetResourceName
49380
+ properties:
49381
+ assetResourceName:
49382
+ type: string
49383
+ pattern: ^customers/\d+/assets/\d+$
49384
+ description: "Asset resource name returned by a list operation. Must belong to the selected\
49385
+ \ customer."
49386
+ structuredSnippetAsset:
49387
+ $ref: '#/components/schemas/GoogleStructuredSnippet'
49388
+ description: "Provide at least one field belonging to this asset type."
49389
+ minItems: 1
49390
+ maxItems: 20
49391
+ example:
49392
+ accountId: 64b1f0c8a1b2c3d4e5f60718
49393
+ customerId: '1234567890'
49394
+ updates:
49395
+ - assetResourceName: customers/1234567890/assets/123
49396
+ structuredSnippetAsset:
49397
+ header: Types
49398
+ values:
49399
+ - Scheduling
49400
+ - Reporting
49401
+ - Messaging
49402
+ responses:
49403
+ '200':
49404
+ description: "Assets returned."
49405
+ content:
49406
+ application/json:
49407
+ schema:
49408
+ type: object
49409
+ properties:
49410
+ updated:
49411
+ type: integer
49412
+ customerId:
49413
+ type: string
49414
+ '400':
49415
+ $ref: '#/components/responses/BadRequest'
49416
+ '401':
49417
+ $ref: '#/components/responses/Unauthorized'
49418
+ '403':
49419
+ description: "Ads access is required."
49420
+ '404':
49421
+ $ref: '#/components/responses/NotFound'
49422
+ '429':
49423
+ description: "Google Ads operations budget or platform quota exhausted."
49424
+ '501':
49425
+ description: "Only supported on Google Ads."
49426
+ delete:
49427
+ operationId: removeAccountStructuredSnippet
49428
+ summary: Remove account snippet
49429
+ x-resource-group: ads
49430
+ tags:
49431
+ - Ad Accounts
49432
+ x-platforms:
49433
+ - google
49434
+ description: "Removes the customer_asset attachment only. The underlying shared asset and its campaign or ad-group\
49435
+ \ attachments remain."
49436
+ security:
49437
+ - bearerAuth: []
49438
+ requestBody:
49439
+ required: true
49440
+ content:
49441
+ application/json:
49442
+ schema:
49443
+ type: object
49444
+ required:
49445
+ - accountId
49446
+ - assetId
49447
+ properties:
49448
+ accountId:
49449
+ type: string
49450
+ pattern: ^[a-fA-F0-9]{24}$
49451
+ description: "Zernio Google Ads connection id."
49452
+ customerId:
49453
+ type: string
49454
+ pattern: ^\d+$
49455
+ description: "Google customer id without dashes. Required when the connection has multiple customers."
49456
+ assetId:
49457
+ type: string
49458
+ pattern: ^\d+$
49459
+ example:
49460
+ accountId: 64b1f0c8a1b2c3d4e5f60718
49461
+ customerId: '1234567890'
49462
+ assetId: '123'
49463
+ responses:
49464
+ '200':
49465
+ description: "Assets returned."
49466
+ content:
49467
+ application/json:
49468
+ schema:
49469
+ type: object
49470
+ properties:
49471
+ removed:
49472
+ type: boolean
49473
+ customerId:
49474
+ type: string
49475
+ '400':
49476
+ $ref: '#/components/responses/BadRequest'
49477
+ '401':
49478
+ $ref: '#/components/responses/Unauthorized'
49479
+ '403':
49480
+ description: "Ads access is required."
49481
+ '404':
49482
+ $ref: '#/components/responses/NotFound'
49483
+ '429':
49484
+ description: "Google Ads operations budget or platform quota exhausted."
49485
+ '501':
49486
+ description: "Only supported on Google Ads."
47809
49487
 
47810
49488
  /v1/ads/accounts/finance:
47811
49489
  get:
@@ -49145,8 +50823,28 @@ paths:
49145
50823
  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." }
49146
50824
  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." }
49147
50825
  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." }
49148
- additionalHeadlines: { type: array, items: { type: string }, description: "Google Search RSA only. Extra headlines." }
49149
- additionalDescriptions: { type: array, items: { type: string }, description: "Google Search RSA only. Extra descriptions." }
50826
+ additionalHeadlines:
50827
+ type: array
50828
+ items:
50829
+ oneOf:
50830
+ - type: string
50831
+ - $ref: '#/components/schemas/GoogleRsaHeadline'
50832
+ description: "Google Search RSA only. Extra text assets as strings or objects with text and optional pinnedField. Existing string input remains supported. The effective create lists, including primary text and deduplication, must contain 3-15 headlines and 2-4 descriptions; excess entries return 400."
50833
+ example:
50834
+ - Schedule Your Posts
50835
+ - text: Build With Zernio
50836
+ pinnedField: HEADLINE_2
50837
+ additionalDescriptions:
50838
+ type: array
50839
+ items:
50840
+ oneOf:
50841
+ - type: string
50842
+ - $ref: '#/components/schemas/GoogleRsaDescription'
50843
+ description: "Google Search RSA only. Extra text assets as strings or objects with text and optional pinnedField. Existing string input remains supported. The effective create lists, including primary text and deduplication, must contain 3-15 headlines and 2-4 descriptions; excess entries return 400."
50844
+ example:
50845
+ - Build social publishing into your application.
50846
+ - text: Connect social accounts with one API.
50847
+ pinnedField: DESCRIPTION_2
49150
50848
  sitelinks:
49151
50849
  type: array
49152
50850
  minItems: 2