late-sdk 0.0.930 → 0.0.932

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/docs/AdCampaignsApi.md +6 -10
  4. data/docs/AdCreative.md +0 -4
  5. data/docs/AdCreativesApi.md +1 -1
  6. data/docs/BoostPostRequest.md +1 -1
  7. data/docs/ConnectApi.md +140 -0
  8. data/docs/CreateAdCreative201Response.md +1 -5
  9. data/docs/CreateAdCreativeRequest.md +2 -2
  10. data/docs/CreateStandaloneAdRequest.md +2 -2
  11. data/docs/CreateStandaloneAdRequestCreativesInner.md +0 -2
  12. data/docs/GetPageWebhookSubscription200Response.md +26 -0
  13. data/docs/ResyncPageWebhookSubscription200Response.md +28 -0
  14. data/docs/UpdateAdRequestCreative.md +2 -2
  15. data/lib/zernio-sdk/api/ad_campaigns_api.rb +4 -7
  16. data/lib/zernio-sdk/api/ad_creatives_api.rb +2 -2
  17. data/lib/zernio-sdk/api/connect_api.rb +126 -0
  18. data/lib/zernio-sdk/models/ad_creative.rb +1 -42
  19. data/lib/zernio-sdk/models/boost_post_request.rb +1 -1
  20. data/lib/zernio-sdk/models/create_ad_creative201_response.rb +4 -44
  21. data/lib/zernio-sdk/models/create_ad_creative_request.rb +3 -2
  22. data/lib/zernio-sdk/models/create_standalone_ad_request.rb +3 -2
  23. data/lib/zernio-sdk/models/create_standalone_ad_request_creatives_inner.rb +1 -11
  24. data/lib/zernio-sdk/models/get_page_webhook_subscription200_response.rb +189 -0
  25. data/lib/zernio-sdk/models/resync_page_webhook_subscription200_response.rb +195 -0
  26. data/lib/zernio-sdk/models/update_ad_request_creative.rb +4 -3
  27. data/lib/zernio-sdk/version.rb +1 -1
  28. data/lib/zernio-sdk.rb +2 -2
  29. data/openapi.yaml +94 -71
  30. data/spec/api/ad_campaigns_api_spec.rb +2 -3
  31. data/spec/api/ad_creatives_api_spec.rb +1 -1
  32. data/spec/api/connect_api_spec.rb +24 -0
  33. data/spec/models/ad_creative_spec.rb +0 -12
  34. data/spec/models/create_ad_creative201_response_spec.rb +0 -12
  35. data/spec/models/create_standalone_ad_request_creatives_inner_spec.rb +0 -6
  36. data/spec/models/{meta_promotion_spec.rb → get_page_webhook_subscription200_response_spec.rb} +11 -15
  37. data/spec/models/resync_page_webhook_subscription200_response_spec.rb +66 -0
  38. data/zernio-sdk-0.0.932.gem +0 -0
  39. metadata +10 -10
  40. data/docs/MetaPromotion.md +0 -26
  41. data/docs/MetaPromotionStatus.md +0 -15
  42. data/lib/zernio-sdk/models/meta_promotion.rb +0 -275
  43. data/lib/zernio-sdk/models/meta_promotion_status.rb +0 -41
  44. data/spec/models/meta_promotion_status_spec.rb +0 -30
  45. data/zernio-sdk-0.0.930.gem +0 -0
@@ -0,0 +1,195 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Zernio
17
+ class ResyncPageWebhookSubscription200Response < ApiModelBase
18
+ attr_accessor :resubscribed
19
+
20
+ attr_accessor :page_id
21
+
22
+ attr_accessor :app_subscribed
23
+
24
+ attr_accessor :leadgen
25
+
26
+ attr_accessor :subscribed_fields
27
+
28
+ attr_accessor :warning
29
+
30
+ # Attribute mapping from ruby-style variable name to JSON key.
31
+ def self.attribute_map
32
+ {
33
+ :'resubscribed' => :'resubscribed',
34
+ :'page_id' => :'pageId',
35
+ :'app_subscribed' => :'appSubscribed',
36
+ :'leadgen' => :'leadgen',
37
+ :'subscribed_fields' => :'subscribedFields',
38
+ :'warning' => :'warning'
39
+ }
40
+ end
41
+
42
+ # Returns attribute mapping this model knows about
43
+ def self.acceptable_attribute_map
44
+ attribute_map
45
+ end
46
+
47
+ # Returns all the JSON keys this model knows about
48
+ def self.acceptable_attributes
49
+ acceptable_attribute_map.values
50
+ end
51
+
52
+ # Attribute type mapping.
53
+ def self.openapi_types
54
+ {
55
+ :'resubscribed' => :'Boolean',
56
+ :'page_id' => :'String',
57
+ :'app_subscribed' => :'Boolean',
58
+ :'leadgen' => :'Boolean',
59
+ :'subscribed_fields' => :'Array<String>',
60
+ :'warning' => :'String'
61
+ }
62
+ end
63
+
64
+ # List of attributes with nullable: true
65
+ def self.openapi_nullable
66
+ Set.new([
67
+ :'warning'
68
+ ])
69
+ end
70
+
71
+ # Initializes the object
72
+ # @param [Hash] attributes Model attributes in the form of hash
73
+ def initialize(attributes = {})
74
+ if (!attributes.is_a?(Hash))
75
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Zernio::ResyncPageWebhookSubscription200Response` initialize method"
76
+ end
77
+
78
+ # check to see if the attribute exists and convert string to symbol for hash key
79
+ acceptable_attribute_map = self.class.acceptable_attribute_map
80
+ attributes = attributes.each_with_object({}) { |(k, v), h|
81
+ if (!acceptable_attribute_map.key?(k.to_sym))
82
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Zernio::ResyncPageWebhookSubscription200Response`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
83
+ end
84
+ h[k.to_sym] = v
85
+ }
86
+
87
+ if attributes.key?(:'resubscribed')
88
+ self.resubscribed = attributes[:'resubscribed']
89
+ end
90
+
91
+ if attributes.key?(:'page_id')
92
+ self.page_id = attributes[:'page_id']
93
+ end
94
+
95
+ if attributes.key?(:'app_subscribed')
96
+ self.app_subscribed = attributes[:'app_subscribed']
97
+ end
98
+
99
+ if attributes.key?(:'leadgen')
100
+ self.leadgen = attributes[:'leadgen']
101
+ end
102
+
103
+ if attributes.key?(:'subscribed_fields')
104
+ if (value = attributes[:'subscribed_fields']).is_a?(Array)
105
+ self.subscribed_fields = value
106
+ end
107
+ end
108
+
109
+ if attributes.key?(:'warning')
110
+ self.warning = attributes[:'warning']
111
+ end
112
+ end
113
+
114
+ # Show invalid properties with the reasons. Usually used together with valid?
115
+ # @return Array for valid properties with the reasons
116
+ def list_invalid_properties
117
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
118
+ invalid_properties = Array.new
119
+ invalid_properties
120
+ end
121
+
122
+ # Check to see if the all the properties in the model are valid
123
+ # @return true if the model is valid
124
+ def valid?
125
+ warn '[DEPRECATED] the `valid?` method is obsolete'
126
+ true
127
+ end
128
+
129
+ # Checks equality by comparing each attribute.
130
+ # @param [Object] Object to be compared
131
+ def ==(o)
132
+ return true if self.equal?(o)
133
+ self.class == o.class &&
134
+ resubscribed == o.resubscribed &&
135
+ page_id == o.page_id &&
136
+ app_subscribed == o.app_subscribed &&
137
+ leadgen == o.leadgen &&
138
+ subscribed_fields == o.subscribed_fields &&
139
+ warning == o.warning
140
+ end
141
+
142
+ # @see the `==` method
143
+ # @param [Object] Object to be compared
144
+ def eql?(o)
145
+ self == o
146
+ end
147
+
148
+ # Calculates hash code according to all attributes.
149
+ # @return [Integer] Hash code
150
+ def hash
151
+ [resubscribed, page_id, app_subscribed, leadgen, subscribed_fields, warning].hash
152
+ end
153
+
154
+ # Builds the object from hash
155
+ # @param [Hash] attributes Model attributes in the form of hash
156
+ # @return [Object] Returns the model itself
157
+ def self.build_from_hash(attributes)
158
+ return nil unless attributes.is_a?(Hash)
159
+ attributes = attributes.transform_keys(&:to_sym)
160
+ transformed_hash = {}
161
+ openapi_types.each_pair do |key, type|
162
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
163
+ transformed_hash["#{key}"] = nil
164
+ elsif type =~ /\AArray<(.*)>/i
165
+ # check to ensure the input is an array given that the attribute
166
+ # is documented as an array but the input is not
167
+ if attributes[attribute_map[key]].is_a?(Array)
168
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
169
+ end
170
+ elsif !attributes[attribute_map[key]].nil?
171
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
172
+ end
173
+ end
174
+ new(transformed_hash)
175
+ end
176
+
177
+ # Returns the object in the form of hash
178
+ # @return [Hash] Returns the object in the form of hash
179
+ def to_hash
180
+ hash = {}
181
+ self.class.attribute_map.each_pair do |attr, param|
182
+ value = self.send(attr)
183
+ if value.nil?
184
+ is_nullable = self.class.openapi_nullable.include?(attr)
185
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
186
+ end
187
+
188
+ hash[param] = _to_hash(value)
189
+ end
190
+ hash
191
+ end
192
+
193
+ end
194
+
195
+ end
@@ -14,11 +14,12 @@ require 'date'
14
14
  require 'time'
15
15
 
16
16
  module Zernio
17
- # Replace or patch the ad's creative. Meta, TikTok, and LinkedIn. - **Meta**: patch-style. Pass any subset: fields you omit are preserved from the live creative, including media (`image_hash`/`video_id` are reused, no re-upload) and `url_tags`. Sending the full set (`headline`, `body`, `callToAction`, `linkUrl`, `imageUrl`) rebuilds the creative from scratch instead. Partial patching reads the live `object_story_spec`, which Meta strips on SHARE / page-post / dark / asset_feed creatives. Those return 422 asking for the full set. A `videoUrl`/`videoId` on an image creative is a type change and also needs the full set. `existingCreativeId` repoints the ad at a creative from GET /v1/ads/creatives and ignores every other field. Meta creatives are immutable, so any change creates a new creative and repoints the ad; the old creative is retained on the ad account for historical reporting. `promotion` and `creativeFeatures` are Meta-only. Omitted settings are preserved from the live creative, including full rebuilds. Send `promotion: null` to remove the explicit offer from the replacement. A supplied creativeFeatures map overrides individual existing keys. - **TikTok**: patch-style. Pass any subset; `headline` is ignored (TikTok creatives have no headline slot). `body` becomes the in-feed `ad_text`; `linkUrl` becomes `landing_page_url`; `videoUrl` triggers a fresh upload. `description`, `videoId` and `existingCreativeId` are Meta-only and return 400. - **LinkedIn**: requires new media (image via `imageUrl` or video via `videoUrl`); a text-only creative update returns 400. Uploads the media, creates a new inline media creative on the same campaign, and pauses the old creative (best-effort). The old creative is retained for historical reporting. `videoId` and `existingCreativeId` are Meta-only and return 400.
17
+ # Replace or patch the ad's creative. Meta, TikTok, and LinkedIn. - **Meta**: patch-style. Pass any subset: fields you omit are preserved from the live creative, including media (`image_hash`/`video_id` are reused, no re-upload) and `url_tags`. Sending the full set (`headline`, `body`, `callToAction`, `linkUrl`, `imageUrl`) rebuilds the creative from scratch instead. Partial patching reads the live `object_story_spec`, which Meta strips on SHARE / page-post / dark / asset_feed creatives. Those return 422 asking for the full set. A `videoUrl`/`videoId` on an image creative is a type change and also needs the full set. `existingCreativeId` repoints the ad at a creative from GET /v1/ads/creatives and ignores every other field. Meta creatives are immutable, so any change creates a new creative and repoints the ad; the old creative is retained on the ad account for historical reporting. `creativeFeatures` is Meta-only. Omitted settings are preserved from the live creative, including full rebuilds. A supplied creativeFeatures map overrides individual existing keys. - **TikTok**: patch-style. Pass any subset; `headline` is ignored (TikTok creatives have no headline slot). `body` becomes the in-feed `ad_text`; `linkUrl` becomes `landing_page_url`; `videoUrl` triggers a fresh upload. `description`, `videoId` and `existingCreativeId` are Meta-only and return 400. - **LinkedIn**: requires new media (image via `imageUrl` or video via `videoUrl`); a text-only creative update returns 400. Uploads the media, creates a new inline media creative on the same campaign, and pauses the old creative (best-effort). The old creative is retained for historical reporting. `videoId` and `existingCreativeId` are Meta-only and return 400.
18
18
  class UpdateAdRequestCreative < ApiModelBase
19
+ # Not supported. Meta validates creative_sourcing_spec.promotion_metadata_spec on the create call and then discards it, so a Promotion set through the Marketing API never reaches the creative. Any object is rejected with 400 invalid_field_value. Send null or omit the field, and set the Promotion on the ad in Ads Manager. Verified on 2026-09-11 across Graph v19.0 to v25.0 and every write path.
19
20
  attr_accessor :promotion
20
21
 
21
- # Meta Advantage+ creative enhancements. Map snake_case feature names to OPT_IN or OPT_OUT; Meta validates supported keys and unspecified features default to OPT_OUT. auto_promotion_tag is an enhancement; use the separate promotion field for an explicit offer. The deprecated standard_enhancements bundle is rejected by Meta.
22
+ # Meta Advantage+ creative enhancements. Map snake_case feature names to OPT_IN or OPT_OUT; Meta validates supported keys and unspecified features default to OPT_OUT. auto_promotion_tag is an Advantage+ enhancement, not the Ads Manager Promotion setting. The deprecated standard_enhancements bundle is rejected by Meta.
22
23
  attr_accessor :creative_features
23
24
 
24
25
  # Meta and LinkedIn (TikTok has no headline slot)
@@ -107,7 +108,7 @@ module Zernio
107
108
  # Attribute type mapping.
108
109
  def self.openapi_types
109
110
  {
110
- :'promotion' => :'MetaPromotion',
111
+ :'promotion' => :'Null',
111
112
  :'creative_features' => :'Hash<String, String>',
112
113
  :'headline' => :'String',
113
114
  :'long_headline' => :'String',
@@ -11,5 +11,5 @@ Generator version: 7.19.0
11
11
  =end
12
12
 
13
13
  module Zernio
14
- VERSION = '0.0.930'
14
+ VERSION = '0.0.932'
15
15
  end
data/lib/zernio-sdk.rb CHANGED
@@ -787,6 +787,7 @@ require 'zernio-sdk/models/get_media_presigned_url200_response'
787
787
  require 'zernio-sdk/models/get_media_presigned_url_request'
788
788
  require 'zernio-sdk/models/get_message_attachment200_response'
789
789
  require 'zernio-sdk/models/get_messenger_menu200_response'
790
+ require 'zernio-sdk/models/get_page_webhook_subscription200_response'
790
791
  require 'zernio-sdk/models/get_pending_o_auth_data200_response'
791
792
  require 'zernio-sdk/models/get_pending_o_auth_data200_response_organizations_inner'
792
793
  require 'zernio-sdk/models/get_phone_number200_response'
@@ -1256,8 +1257,6 @@ require 'zernio-sdk/models/meta_ads_platform_data'
1256
1257
  require 'zernio-sdk/models/meta_instagram_identity_ref'
1257
1258
  require 'zernio-sdk/models/meta_lead_form_platform_data'
1258
1259
  require 'zernio-sdk/models/meta_lead_form_platform_data_context_card'
1259
- require 'zernio-sdk/models/meta_promotion'
1260
- require 'zernio-sdk/models/meta_promotion_status'
1261
1260
  require 'zernio-sdk/models/money'
1262
1261
  require 'zernio-sdk/models/money_amount'
1263
1262
  require 'zernio-sdk/models/move_account_to_profile200_response'
@@ -1399,6 +1398,7 @@ require 'zernio-sdk/models/respond_to_sms_registration_review200_response'
1399
1398
  require 'zernio-sdk/models/respond_to_sms_registration_review_request'
1400
1399
  require 'zernio-sdk/models/restore_workflow_version200_response'
1401
1400
  require 'zernio-sdk/models/restore_workflow_version200_response_workflow'
1401
+ require 'zernio-sdk/models/resync_page_webhook_subscription200_response'
1402
1402
  require 'zernio-sdk/models/retry_post207_response'
1403
1403
  require 'zernio-sdk/models/retweet_post200_response'
1404
1404
  require 'zernio-sdk/models/retweet_post_request'
data/openapi.yaml CHANGED
@@ -9256,32 +9256,12 @@ components:
9256
9256
  type: object
9257
9257
  additionalProperties: { type: string, enum: [OPT_IN, OPT_OUT] }
9258
9258
  propertyNames: { pattern: '^[a-z0-9_]+$' }
9259
- description: 'Meta Advantage+ creative enhancements. Map snake_case feature names to OPT_IN or OPT_OUT; Meta validates supported keys and unspecified features default to OPT_OUT. auto_promotion_tag is an enhancement; use the separate promotion field for an explicit offer. The deprecated standard_enhancements bundle is rejected by Meta.'
9259
+ description: 'Meta Advantage+ creative enhancements. Map snake_case feature names to OPT_IN or OPT_OUT; Meta validates supported keys and unspecified features default to OPT_OUT. auto_promotion_tag is an Advantage+ enhancement, not the Ads Manager Promotion setting. The deprecated standard_enhancements bundle is rejected by Meta.'
9260
9260
  example: { auto_promotion_tag: OPT_IN }
9261
9261
  MetaPromotion:
9262
- type: [object, "null"]
9263
- description: 'Meta explicit Promotion offer. Maps to creative_sourcing_spec.promotion_metadata_spec with promotion_source ADVERTISER_INPUT. Dates become Unix seconds. Send null to omit an explicit offer on a new creative or remove it when rebuilding. Creation success alone does not confirm application: inspect promotionStatus in the response.'
9264
- required: [type, value]
9265
- properties:
9266
- type:
9267
- type: string
9268
- enum: [AMOUNT_OFF, FREE_RETURN, FREE_SHIPPING, PERCENTAGE_OFF, PROMO_CODE]
9269
- description: 'Promotion type accepted by Meta. PERCENTAGE_OFF values cannot exceed 100.'
9270
- value: { type: number, minimum: 0, description: 'Nonnegative promotion value passed to Meta unchanged. AMOUNT_OFF units are not confirmed, including major versus minor currency units. For PERCENTAGE_OFF this is the percentage discount, at most 100.' }
9271
- code: { type: string, minLength: 1, description: 'Optional promotion code.' }
9272
- startDate: { type: string, format: date-time, description: 'Optional ISO 8601 start timestamp with a timezone offset or Z.' }
9273
- endDate: { type: string, format: date-time, description: 'Optional ISO 8601 end timestamp with a timezone offset or Z. Must be after startDate when both are set.' }
9274
- example:
9275
- type: PERCENTAGE_OFF
9276
- value: 20
9277
- code: SAVE20
9278
- startDate: '2026-10-01T00:00:00Z'
9279
- endDate: '2026-10-31T23:59:59Z'
9280
- MetaPromotionStatus:
9281
- type: string
9282
- enum: [applied, not_returned, unavailable]
9283
- 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.'
9284
- example: not_returned
9262
+ type: "null"
9263
+ description: 'Not supported. Meta validates creative_sourcing_spec.promotion_metadata_spec on the create call and then discards it, so a Promotion set through the Marketing API never reaches the creative. Any object is rejected with 400 invalid_field_value. Send null or omit the field, and set the Promotion on the ad in Ads Manager. Verified on 2026-09-11 across Graph v19.0 to v25.0 and every write path.'
9264
+ example: null
9285
9265
  GoogleSitelink:
9286
9266
  type: object
9287
9267
  required:
@@ -9745,10 +9725,6 @@ components:
9745
9725
  imageUrl: { type: string, description: Alternative image URL }
9746
9726
  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." }
9747
9727
  videoUrl: { type: [string, "null"], description: "Public Facebook watch URL for VIDEO-type ads (https://www.facebook.com/watch/?v={videoId}). Null for non-video ads." }
9748
- promotion:
9749
- $ref: '#/components/schemas/MetaPromotion'
9750
- description: 'Meta offer read from the live creative on creation or GET /v1/ads/{adId}. Null when metadata is not returned or cannot be read. Requested values are never echoed as applied.'
9751
- promotionStatus: { $ref: '#/components/schemas/MetaPromotionStatus' }
9752
9728
  creativeId: { type: [string, "null"], description: "Meta ad creative id backing this ad. Reusable via existingCreativeId on POST /v1/ads/create." }
9753
9729
  objectType: { type: string, description: "Meta creative object_type (e.g. SHARE, VIDEO, PRIVACY_CHECK_FAIL, POST_DELETED). Use this to render state-aware previews: when Meta moderation strips image/video fields, only thumbnailUrl at 64x64 is available." }
9754
9730
  objectStoryId: { type: [string, "null"], description: "Meta creative `object_story_id` (the SHARE reference). Frequently absent, because Meta omits it for SHARE creatives. Use effectiveObjectStoryId instead." }
@@ -24234,6 +24210,73 @@ paths:
24234
24210
  '404': { description: Code not found }
24235
24211
  '500': { description: Internal error }
24236
24212
 
24213
+ /v1/accounts/{accountId}/webhook-subscription:
24214
+ get:
24215
+ x-resource-group: "accounts"
24216
+ operationId: getPageWebhookSubscription
24217
+ tags: [Connect]
24218
+ summary: Read a Facebook Page's webhook subscription
24219
+ description: |
24220
+ Returns the webhook fields Zernio's app is subscribed to on the connected Page, read live from Meta.
24221
+ Use it to confirm `leadgen` is present: a Page missing it keeps delivering every other event while
24222
+ lead ads stop arriving, with nothing to indicate it.
24223
+ parameters:
24224
+ - name: accountId
24225
+ in: path
24226
+ required: true
24227
+ schema: { type: string }
24228
+ responses:
24229
+ '200':
24230
+ description: The Page's current subscription
24231
+ content:
24232
+ application/json:
24233
+ schema:
24234
+ type: object
24235
+ properties:
24236
+ pageId: { type: string }
24237
+ appSubscribed: { type: boolean, description: 'False when the Page carries no subscription for our app at all.' }
24238
+ leadgen: { type: boolean, description: 'Whether lead ads submitted on this Page reach Zernio in real time.' }
24239
+ subscribedFields: { type: array, items: { type: string } }
24240
+ warning: { type: [string, 'null'], description: 'Present only when leadgen is missing.' }
24241
+ '400': { $ref: '#/components/responses/BadRequest' }
24242
+ '404': { $ref: '#/components/responses/NotFound' }
24243
+ '409':
24244
+ description: The connection has no selected Page
24245
+ post:
24246
+ x-resource-group: "accounts"
24247
+ operationId: resyncPageWebhookSubscription
24248
+ tags: [Connect]
24249
+ summary: Re-subscribe a Facebook Page to Zernio's webhooks
24250
+ description: |
24251
+ Re-sends the full field set to Meta and returns the subscription read back afterwards.
24252
+ Meta only honours the field set sent at subscribe time, so a Page connected before a field
24253
+ existed stays without it until this runs. The response reflects what Meta actually granted,
24254
+ not what was requested.
24255
+ parameters:
24256
+ - name: accountId
24257
+ in: path
24258
+ required: true
24259
+ schema: { type: string }
24260
+ responses:
24261
+ '200':
24262
+ description: The subscription after re-subscribing
24263
+ content:
24264
+ application/json:
24265
+ schema:
24266
+ type: object
24267
+ properties:
24268
+ resubscribed: { type: boolean }
24269
+ pageId: { type: string }
24270
+ appSubscribed: { type: boolean }
24271
+ leadgen: { type: boolean }
24272
+ subscribedFields: { type: array, items: { type: string } }
24273
+ warning: { type: [string, 'null'] }
24274
+ '400': { $ref: '#/components/responses/BadRequest' }
24275
+ '404': { $ref: '#/components/responses/NotFound' }
24276
+ '409':
24277
+ description: The connection has no selected Page
24278
+ '502':
24279
+ description: Meta rejected the subscription
24237
24280
  /v1/accounts/{accountId}/facebook-page:
24238
24281
  get:
24239
24282
  x-resource-group: "accounts"
@@ -45321,19 +45364,11 @@ paths:
45321
45364
  - the creative's `effective_instagram_media_id` (Instagram side)
45322
45365
 
45323
45366
  Any of the four resolve to the same ad. Caller doesn't need a translation step.
45324
- By default, creative.promotion and creative.creativeFeatures contain stored requested
45325
- settings, which do not confirm platform application. With `refreshPromotion=true`,
45326
- Meta promotion metadata is read live and exposed as `ad.creative.promotion`
45327
- with `promotionStatus`. Only `applied` confirms an offer; `not_returned` means the
45328
- creative read succeeded without promotion metadata, and `unavailable` means it failed.
45367
+ `creative.creativeFeatures` holds the stored requested settings, which do not confirm
45368
+ platform application.
45329
45369
  security:
45330
45370
  - bearerAuth: []
45331
45371
  parameters:
45332
- - name: refreshPromotion
45333
- in: query
45334
- required: false
45335
- schema: { type: boolean, default: false }
45336
- description: 'Meta only. Read current promotion metadata from Meta and include promotionStatus. Omit for stored creative settings with no promotion-specific Graph call.'
45337
45372
  - name: adId
45338
45373
  in: path
45339
45374
  required: true
@@ -45494,11 +45529,10 @@ paths:
45494
45529
  longHeadline: Schedule social content from your app with Zernio
45495
45530
  imageUrl: 'https://example.com/new-landscape.png'
45496
45531
  squareImageUrl: 'https://example.com/new-square.png'
45497
- metaPromotion:
45498
- summary: "Remove a Meta promotion."
45532
+ metaCreativeFeatures:
45533
+ summary: "Opt a Meta creative out of an Advantage+ enhancement."
45499
45534
  value:
45500
45535
  creative:
45501
- promotion: null
45502
45536
  creativeFeatures: { auto_promotion_tag: OPT_OUT }
45503
45537
  schema:
45504
45538
  type: object
@@ -45629,10 +45663,9 @@ paths:
45629
45663
  GET /v1/ads/creatives and ignores every other field. Meta creatives are
45630
45664
  immutable, so any change creates a new creative and repoints the ad; the old
45631
45665
  creative is retained on the ad account for historical reporting.
45632
- `promotion` and `creativeFeatures` are Meta-only. Omitted settings are
45633
- preserved from the live creative, including full rebuilds. Send
45634
- `promotion: null` to remove the explicit offer from the replacement.
45635
- A supplied creativeFeatures map overrides individual existing keys.
45666
+ `creativeFeatures` is Meta-only. Omitted settings are preserved from the
45667
+ live creative, including full rebuilds. A supplied creativeFeatures map
45668
+ overrides individual existing keys.
45636
45669
  - **TikTok**: patch-style. Pass any subset; `headline` is ignored (TikTok creatives
45637
45670
  have no headline slot). `body` becomes the in-feed `ad_text`; `linkUrl` becomes
45638
45671
  `landing_page_url`; `videoUrl` triggers a fresh upload. `description`, `videoId`
@@ -45643,7 +45676,9 @@ paths:
45643
45676
  The old creative is retained for historical reporting. `videoId` and
45644
45677
  `existingCreativeId` are Meta-only and return 400.
45645
45678
  properties:
45646
- promotion: { $ref: '#/components/schemas/MetaPromotion' }
45679
+ promotion:
45680
+ $ref: '#/components/schemas/MetaPromotion'
45681
+ description: 'Not supported. Meta validates creative_sourcing_spec.promotion_metadata_spec on the create call and then discards it, so a Promotion set through the Marketing API never reaches the creative. Any object is rejected with 400 invalid_field_value. Send null or omit the field, and set the Promotion on the ad in Ads Manager. Verified on 2026-09-11 across Graph v19.0 to v25.0 and every write path.'
45647
45682
  creativeFeatures: { $ref: '#/components/schemas/MetaCreativeFeatures' }
45648
45683
  headline: { type: string, description: "Meta and LinkedIn (TikTok has no headline slot)" }
45649
45684
  longHeadline: { type: string, minLength: 1, maxLength: 90, description: "Google Display only. Replaces the responsive display ad's long headline." }
@@ -48175,11 +48210,8 @@ paths:
48175
48210
  `existingCreativeId`. Provide exactly one of `imageUrl` (uploaded server-side),
48176
48211
  `imageHash` (from POST /v1/ads/images or the library list), or `carouselCards` (2-10
48177
48212
  hand-built cards). The Page (and linked Instagram account, when present) is resolved
48178
- from `accountId` as the story actor. `promotion` configures an explicit offer separately
48179
- from Advantage+ `creativeFeatures`. Only when `promotion` is supplied does the response
48180
- read the creative back from Meta;
48181
- `promotionStatus: not_returned` means Meta accepted creation but omitted promotion
48182
- metadata, so the requested offer is not confirmed as applied.
48213
+ from `accountId` as the story actor. `creativeFeatures` configures Advantage+
48214
+ enhancements. `promotion` is not supported and any object is rejected with 400.
48183
48215
  security:
48184
48216
  - bearerAuth: []
48185
48217
  requestBody:
@@ -48213,10 +48245,12 @@ paths:
48213
48245
  description: { type: string, maxLength: 255 }
48214
48246
  callToAction: { type: string }
48215
48247
  urlTags: { type: string, description: "Appended to every outbound URL (e.g. utm_source=fb)." }
48216
- promotion: { $ref: '#/components/schemas/MetaPromotion' }
48248
+ promotion:
48249
+ $ref: '#/components/schemas/MetaPromotion'
48250
+ description: 'Not supported. Meta validates creative_sourcing_spec.promotion_metadata_spec on the create call and then discards it, so a Promotion set through the Marketing API never reaches the creative. Any object is rejected with 400 invalid_field_value. Send null or omit the field, and set the Promotion on the ad in Ads Manager. Verified on 2026-09-11 across Graph v19.0 to v25.0 and every write path.'
48217
48251
  creativeFeatures:
48218
48252
  $ref: '#/components/schemas/MetaCreativeFeatures'
48219
- description: 'Meta only. Applied to each new creative, including standalone and attach shapes. With creatives[], these are defaults; an item replaces the whole feature map, including an empty map. auto_promotion_tag is an enhancement; an explicit offer uses promotion.'
48253
+ description: 'Meta only. Applied to each new creative, including standalone and attach shapes. With creatives[], these are defaults; an item replaces the whole feature map, including an empty map. auto_promotion_tag is an Advantage+ enhancement, not the Ads Manager Promotion setting.'
48220
48254
  multiAdvertiser:
48221
48255
  type: string
48222
48256
  enum: [OPT_IN, OPT_OUT]
@@ -48228,7 +48262,6 @@ paths:
48228
48262
  body: Use SAVE20 at checkout.
48229
48263
  linkUrl: https://example.com/shop
48230
48264
  imageUrl: https://example.com/ad.jpg
48231
- promotion: { type: PERCENTAGE_OFF, value: 20, code: SAVE20 }
48232
48265
  creativeFeatures: { auto_promotion_tag: OPT_OUT }
48233
48266
  responses:
48234
48267
  '409': { $ref: '#/components/responses/AccountConnectionRequired' }
@@ -48242,13 +48275,9 @@ paths:
48242
48275
  properties:
48243
48276
  adAccountId: { type: string }
48244
48277
  creativeId: { type: string, description: "Platform creative id, reusable via existingCreativeId." }
48245
- promotion: { $ref: '#/components/schemas/MetaPromotion' }
48246
- promotionStatus: { $ref: '#/components/schemas/MetaPromotionStatus' }
48247
48278
  example:
48248
48279
  adAccountId: act_123456789
48249
48280
  creativeId: '123456789012345'
48250
- promotion: null
48251
- promotionStatus: not_returned
48252
48281
  '400': { description: "Invalid input, or Meta rejected the create" }
48253
48282
  '401': { $ref: '#/components/responses/Unauthorized' }
48254
48283
  '422': { description: No Facebook Page found to act as the story actor }
@@ -51142,15 +51171,11 @@ paths:
51142
51171
  - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting.
51143
51172
  - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted.
51144
51173
 
51145
- Meta accepts `promotion` and `creativeFeatures` on the single and attach shapes and
51146
- as defaults for `creatives[]`. An item replaces the whole feature map; its `promotion`
51147
- replaces the default offer, and `promotion: null` disables that default for the item.
51174
+ Meta accepts `creativeFeatures` on the single and attach shapes and as defaults for
51175
+ `creatives[]`; an item replaces the whole feature map. `promotion` is not supported on any
51176
+ shape and any object is rejected with 400.
51148
51177
  Reusing `existingCreativeId` uses the existing creative settings instead of new settings.
51149
51178
  Requested settings are persisted for lists, exports, and default ad-detail reads.
51150
- Only ads supplied a `promotion` receive live readback; multi-create batches those reads
51151
- in groups of up to 50 IDs without per-ad fallback. Inspect `ad.creative.promotionStatus` (or
51152
- `ads[].creative.promotionStatus`). `not_returned` means Meta omitted the metadata;
51153
- successful creation does not by itself prove the offer was applied or will display.
51154
51179
 
51155
51180
  Per-platform required fields, budget minimums, and video-ad rules are documented on each property below.
51156
51181
 
@@ -51205,10 +51230,12 @@ paths:
51205
51230
  billingEvent: { type: string, description: "Meta only. Explicit ad-set `billing_event`. Defaults to `IMPRESSIONS`. Forwarded verbatim to Meta, which validates compatibility with the optimization goal." }
51206
51231
  buyingType: { type: string, enum: [AUCTION, RESERVED], default: AUCTION, description: "Meta only. Defaults to AUCTION and is explicitly sent on new campaigns, including validateOnly. Reusing existingCampaignId does not change the campaign. RESERVED = Reach & Frequency: requires `rfPredictionId` (a RESERVED prediction from /v1/ads/rf-predictions + /reserve). Budget, schedule and pricing come from the reservation, so budgetAmount/budgetType are not required and bid fields are ignored. Only the plain single-ad shape (no creatives[], adSetId, existingCampaignId or dynamicCreative)." }
51207
51232
  rfPredictionId: { type: string, description: "Meta only. The RESERVED prediction id the R&F ad set runs on (reserving mints a new id, so pass that one). Requires buyingType RESERVED." }
51208
- promotion: { $ref: '#/components/schemas/MetaPromotion' }
51233
+ promotion:
51234
+ $ref: '#/components/schemas/MetaPromotion'
51235
+ description: 'Not supported. Meta validates creative_sourcing_spec.promotion_metadata_spec on the create call and then discards it, so a Promotion set through the Marketing API never reaches the creative. Any object is rejected with 400 invalid_field_value. Send null or omit the field, and set the Promotion on the ad in Ads Manager. Verified on 2026-09-11 across Graph v19.0 to v25.0 and every write path.'
51209
51236
  creativeFeatures:
51210
51237
  $ref: '#/components/schemas/MetaCreativeFeatures'
51211
- description: 'Meta only. Applied to each new creative, including standalone and attach shapes. With creatives[], these are defaults; an item replaces the whole feature map, including an empty map. auto_promotion_tag is an enhancement; an explicit offer uses promotion.'
51238
+ description: 'Meta only. Applied to each new creative, including standalone and attach shapes. With creatives[], these are defaults; an item replaces the whole feature map, including an empty map. auto_promotion_tag is an Advantage+ enhancement, not the Ads Manager Promotion setting.'
51212
51239
  multiAdvertiser:
51213
51240
  type: string
51214
51241
  enum: [OPT_IN, OPT_OUT]
@@ -51308,9 +51335,6 @@ paths:
51308
51335
  required: [headline, body, linkUrl, callToAction]
51309
51336
  description: "Each creative must supply EXACTLY ONE of `imageUrl` (image creative) or `video` (video creative)."
51310
51337
  properties:
51311
- promotion:
51312
- $ref: '#/components/schemas/MetaPromotion'
51313
- description: 'Overrides the top-level offer for this item. Omit to inherit; null disables the inherited offer.'
51314
51338
  creativeFeatures:
51315
51339
  $ref: '#/components/schemas/MetaCreativeFeatures'
51316
51340
  description: 'Replaces the entire top-level creativeFeatures map for this item. Omit to inherit; an empty map clears these defaults.'
@@ -52233,7 +52257,6 @@ paths:
52233
52257
  callToAction: SHOP_NOW
52234
52258
  linkUrl: https://example.com/shop
52235
52259
  imageUrl: https://example.com/ad.jpg
52236
- promotion: { type: PERCENTAGE_OFF, value: 20, code: SAVE20 }
52237
52260
  creativeFeatures: { auto_promotion_tag: OPT_OUT }
52238
52261
  responses:
52239
52262
  '409': { $ref: '#/components/responses/AccountConnectionRequired' }
@@ -135,7 +135,7 @@ describe 'AdCampaignsApi' do
135
135
 
136
136
  # unit tests for create_standalone_ad
137
137
  # Create standalone ad
138
- # Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads). Google Performance Max: set &#x60;campaignType: \&quot;pmax\&quot;&#x60; and supply &#x60;assetGroup&#x60; with text, images by role, business name and finalUrl. Creates a daily budget, PAUSED campaign and asset group atomically. &#x60;validateOnly: true&#x60; validates the complete request with Google without creating or persisting resources. Read assets with &#x60;GET /v1/ads/campaigns/{campaignId}/asset-groups&#x60;. The logo is required; video is optional via &#x60;assetGroup.youtubeVideoId&#x60;. Brand guidelines are disabled at creation. All supplied asset links are validated together against Google&#39;s minimum asset requirements. PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields and attach shapes. Geo and language targeting are supported; omitted geo targets all locations. PMax does not require top-level goal, headline, body or linkUrl. Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for Maximize Conversion Value with target ROAS. Other mutually-exclusive request shapes are selected by the body: - Legacy single-creative shape (all platforms, the default). - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting. - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted. Meta accepts &#x60;promotion&#x60; and &#x60;creativeFeatures&#x60; on the single and attach shapes and as defaults for &#x60;creatives[]&#x60;. An item replaces the whole feature map; its &#x60;promotion&#x60; replaces the default offer, and &#x60;promotion: null&#x60; disables that default for the item. Reusing &#x60;existingCreativeId&#x60; uses the existing creative settings instead of new settings. Requested settings are persisted for lists, exports, and default ad-detail reads. Only ads supplied a &#x60;promotion&#x60; receive live readback; multi-create batches those reads in groups of up to 50 IDs without per-ad fallback. Inspect &#x60;ad.creative.promotionStatus&#x60; (or &#x60;ads[].creative.promotionStatus&#x60;). &#x60;not_returned&#x60; means Meta omitted the metadata; successful creation does not by itself prove the offer was applied or will display. Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content \&quot;dark post\&quot; authored by a Company Page (see &#x60;organizationId&#x60;). Supported goals are engagement, traffic, awareness, and video_views (video ads use the &#x60;video&#x60; field; video_views requires a video), and traffic ads require &#x60;linkUrl&#x60;. **Idempotency:** this endpoint is not idempotent at the platform level (a blind retry creates a second campaign/ad set/ad). Send an &#x60;Idempotency-Key&#x60; header to make retries safe: the first request with a given key creates the ad and we store the response; a retry with the same key replays that exact response (with &#x60;Idempotent-Replayed: true&#x60;) instead of creating duplicates. Reusing a key with a different body returns 422; a key whose first request is still in flight returns 409 (retry after a short backoff). Keys are scoped to your credential and expire after 24h.
138
+ # Create a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X, LinkedIn, and OpenAI Ads (ChatGPT Ads). Google Performance Max: set &#x60;campaignType: \&quot;pmax\&quot;&#x60; and supply &#x60;assetGroup&#x60; with text, images by role, business name and finalUrl. Creates a daily budget, PAUSED campaign and asset group atomically. &#x60;validateOnly: true&#x60; validates the complete request with Google without creating or persisting resources. Read assets with &#x60;GET /v1/ads/campaigns/{campaignId}/asset-groups&#x60;. The logo is required; video is optional via &#x60;assetGroup.youtubeVideoId&#x60;. Brand guidelines are disabled at creation. All supplied asset links are validated together against Google&#39;s minimum asset requirements. PMax rejects ACTIVE creation, portfolio bidding, bid caps, legacy creative fields and attach shapes. Geo and language targeting are supported; omitted geo targets all locations. PMax does not require top-level goal, headline, body or linkUrl. Supported bidding: omitted or LOWEST_COST_WITHOUT_CAP for Maximize Conversions, COST_CAP plus bidAmount for target CPA, LOWEST_COST_WITH_MIN_ROAS plus roasAverageFloor for Maximize Conversion Value with target ROAS. Other mutually-exclusive request shapes are selected by the body: - Legacy single-creative shape (all platforms, the default). - Meta-only multi-creative shape via the creatives array: one ad set with N ads sharing budget and targeting. - Attach shape via adSetId: adds one new ad to an existing ad set, inheriting its budget, targeting, and schedule (Meta, Google Ads, TikTok, and LinkedIn). On LinkedIn adSetId is the existing Campaign id, and the budget, schedule, targeting and bidding fields must be omitted. Meta accepts &#x60;creativeFeatures&#x60; on the single and attach shapes and as defaults for &#x60;creatives[]&#x60;; an item replaces the whole feature map. &#x60;promotion&#x60; is not supported on any shape and any object is rejected with 400. Reusing &#x60;existingCreativeId&#x60; uses the existing creative settings instead of new settings. Requested settings are persisted for lists, exports, and default ad-detail reads. Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content \&quot;dark post\&quot; authored by a Company Page (see &#x60;organizationId&#x60;). Supported goals are engagement, traffic, awareness, and video_views (video ads use the &#x60;video&#x60; field; video_views requires a video), and traffic ads require &#x60;linkUrl&#x60;. **Idempotency:** this endpoint is not idempotent at the platform level (a blind retry creates a second campaign/ad set/ad). Send an &#x60;Idempotency-Key&#x60; header to make retries safe: the first request with a given key creates the ad and we store the response; a retry with the same key replays that exact response (with &#x60;Idempotent-Replayed: true&#x60;) instead of creating duplicates. Reusing a key with a different body returns 422; a key whose first request is still in flight returns 409 (retry after a short backoff). Keys are scoped to your credential and expire after 24h.
139
139
  # @param create_standalone_ad_request
140
140
  # @param [Hash] opts the optional parameters
141
141
  # @option opts [String] :idempotency_key Optional client-generated unique key (e.g. a UUID) that makes retries safe. Same key + same body replays the original response; same key + different body → 422; key still processing → 409.
@@ -227,10 +227,9 @@ describe 'AdCampaignsApi' do
227
227
 
228
228
  # unit tests for get_ad
229
229
  # Get ad details
230
- # Returns an ad with its creative, targeting, status, and performance metrics. Google Search ads include current creative.headlines, creative.descriptions and creative.finalUrls, preserving pinnedField. Top-level cachedAt and stale report cache freshness. Google mutations invalidate this read. RSA enrichment requires a stored advertisingChannelType of SEARCH. Ads with an unknown or other channel return their stored details without a Google read. If RSA enrichment fails, the stored ad is returned with HTTP 200 and without cache metadata. The &#x60;{adId}&#x60; path segment accepts any identifier dialect Zernio indexes for the ad: - the Zernio internal &#x60;_id&#x60; (24-char hex) - Meta&#39;s numeric &#x60;platformAdId&#x60; (the value shipped in &#x60;comment.received&#x60; webhooks as &#x60;comment.ad.id&#x60;) - the creative&#39;s &#x60;effective_object_story_id&#x60; (&#x60;{pageId}_{postId}&#x60; shape, Facebook side) - the creative&#39;s &#x60;effective_instagram_media_id&#x60; (Instagram side) Any of the four resolve to the same ad. Caller doesn&#39;t need a translation step. By default, creative.promotion and creative.creativeFeatures contain stored requested settings, which do not confirm platform application. With &#x60;refreshPromotion&#x3D;true&#x60;, Meta promotion metadata is read live and exposed as &#x60;ad.creative.promotion&#x60; with &#x60;promotionStatus&#x60;. Only &#x60;applied&#x60; confirms an offer; &#x60;not_returned&#x60; means the creative read succeeded without promotion metadata, and &#x60;unavailable&#x60; means it failed.
230
+ # Returns an ad with its creative, targeting, status, and performance metrics. Google Search ads include current creative.headlines, creative.descriptions and creative.finalUrls, preserving pinnedField. Top-level cachedAt and stale report cache freshness. Google mutations invalidate this read. RSA enrichment requires a stored advertisingChannelType of SEARCH. Ads with an unknown or other channel return their stored details without a Google read. If RSA enrichment fails, the stored ad is returned with HTTP 200 and without cache metadata. The &#x60;{adId}&#x60; path segment accepts any identifier dialect Zernio indexes for the ad: - the Zernio internal &#x60;_id&#x60; (24-char hex) - Meta&#39;s numeric &#x60;platformAdId&#x60; (the value shipped in &#x60;comment.received&#x60; webhooks as &#x60;comment.ad.id&#x60;) - the creative&#39;s &#x60;effective_object_story_id&#x60; (&#x60;{pageId}_{postId}&#x60; shape, Facebook side) - the creative&#39;s &#x60;effective_instagram_media_id&#x60; (Instagram side) Any of the four resolve to the same ad. Caller doesn&#39;t need a translation step. &#x60;creative.creativeFeatures&#x60; holds the stored requested settings, which do not confirm platform application.
231
231
  # @param ad_id Zernio &#x60;_id&#x60; (hex), Meta &#x60;platformAdId&#x60; (numeric), or one of the creative&#39;s effective story/media IDs. See description for details.
232
232
  # @param [Hash] opts the optional parameters
233
- # @option opts [Boolean] :refresh_promotion Meta only. Read current promotion metadata from Meta and include promotionStatus. Omit for stored creative settings with no promotion-specific Graph call.
234
233
  # @return [GetAd200Response]
235
234
  describe 'get_ad test' do
236
235
  it 'should work' do
@@ -34,7 +34,7 @@ describe 'AdCreativesApi' do
34
34
 
35
35
  # unit tests for create_ad_creative
36
36
  # Create a standalone creative
37
- # Creates a creative in the library WITHOUT an ad, reusable on the create endpoints via &#x60;existingCreativeId&#x60;. Provide exactly one of &#x60;imageUrl&#x60; (uploaded server-side), &#x60;imageHash&#x60; (from POST /v1/ads/images or the library list), or &#x60;carouselCards&#x60; (2-10 hand-built cards). The Page (and linked Instagram account, when present) is resolved from &#x60;accountId&#x60; as the story actor. &#x60;promotion&#x60; configures an explicit offer separately from Advantage+ &#x60;creativeFeatures&#x60;. Only when &#x60;promotion&#x60; is supplied does the response read the creative back from Meta; &#x60;promotionStatus: not_returned&#x60; means Meta accepted creation but omitted promotion metadata, so the requested offer is not confirmed as applied.
37
+ # Creates a creative in the library WITHOUT an ad, reusable on the create endpoints via &#x60;existingCreativeId&#x60;. Provide exactly one of &#x60;imageUrl&#x60; (uploaded server-side), &#x60;imageHash&#x60; (from POST /v1/ads/images or the library list), or &#x60;carouselCards&#x60; (2-10 hand-built cards). The Page (and linked Instagram account, when present) is resolved from &#x60;accountId&#x60; as the story actor. &#x60;creativeFeatures&#x60; configures Advantage+ enhancements. &#x60;promotion&#x60; is not supported and any object is rejected with 400.
38
38
  # @param create_ad_creative_request
39
39
  # @param [Hash] opts the optional parameters
40
40
  # @return [CreateAdCreative201Response]