late-sdk 0.0.644 → 0.0.646

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/docs/AdCampaignsApi.md +2 -2
  4. data/docs/AdDailyMetrics.md +1 -1
  5. data/docs/AdMetrics.md +1 -1
  6. data/docs/AdTreeCampaign.md +1 -1
  7. data/docs/GetAdsTimeline200ResponseRowsInner.md +1 -1
  8. data/docs/GetCampaignAnalytics200ResponseAnalyticsDailyInner.md +1 -1
  9. data/docs/GetInboxConversation200ResponseData.md +3 -1
  10. data/docs/GetInboxConversation200ResponseDataMetadata.md +38 -0
  11. data/docs/ListInboxConversations200ResponseDataInner.md +3 -1
  12. data/docs/ListInboxConversations200ResponseDataInnerMetadata.md +50 -0
  13. data/lib/zernio-sdk/api/ad_campaigns_api.rb +2 -2
  14. data/lib/zernio-sdk/api/messages_api.rb +1 -1
  15. data/lib/zernio-sdk/models/ad_daily_metrics.rb +2 -1
  16. data/lib/zernio-sdk/models/ad_metrics.rb +1 -0
  17. data/lib/zernio-sdk/models/ad_tree_campaign.rb +1 -1
  18. data/lib/zernio-sdk/models/get_ads_timeline200_response_rows_inner.rb +1 -0
  19. data/lib/zernio-sdk/models/get_campaign_analytics200_response_analytics_daily_inner.rb +1 -0
  20. data/lib/zernio-sdk/models/get_inbox_conversation200_response_data.rb +13 -4
  21. data/lib/zernio-sdk/models/get_inbox_conversation200_response_data_metadata.rb +249 -0
  22. data/lib/zernio-sdk/models/list_inbox_conversations200_response_data_inner.rb +13 -4
  23. data/lib/zernio-sdk/models/list_inbox_conversations200_response_data_inner_metadata.rb +309 -0
  24. data/lib/zernio-sdk/version.rb +1 -1
  25. data/lib/zernio-sdk.rb +2 -0
  26. data/openapi.yaml +158 -6
  27. data/spec/api/ad_campaigns_api_spec.rb +1 -1
  28. data/spec/models/get_inbox_conversation200_response_data_metadata_spec.rb +96 -0
  29. data/spec/models/get_inbox_conversation200_response_data_spec.rb +6 -0
  30. data/spec/models/list_inbox_conversations200_response_data_inner_metadata_spec.rb +132 -0
  31. data/spec/models/list_inbox_conversations200_response_data_inner_spec.rb +6 -0
  32. data/zernio-sdk-0.0.646.gem +0 -0
  33. metadata +10 -2
  34. data/zernio-sdk-0.0.644.gem +0 -0
@@ -47,6 +47,8 @@ module Zernio
47
47
 
48
48
  attr_accessor :instagram_profile
49
49
 
50
+ attr_accessor :metadata
51
+
50
52
  class EnumAttributeValidator
51
53
  attr_reader :datatype
52
54
  attr_reader :allowable_values
@@ -85,7 +87,8 @@ module Zernio
85
87
  :'status' => :'status',
86
88
  :'unread_count' => :'unreadCount',
87
89
  :'url' => :'url',
88
- :'instagram_profile' => :'instagramProfile'
90
+ :'instagram_profile' => :'instagramProfile',
91
+ :'metadata' => :'metadata'
89
92
  }
90
93
  end
91
94
 
@@ -115,7 +118,8 @@ module Zernio
115
118
  :'status' => :'String',
116
119
  :'unread_count' => :'Integer',
117
120
  :'url' => :'String',
118
- :'instagram_profile' => :'ListInboxConversations200ResponseDataInnerInstagramProfile'
121
+ :'instagram_profile' => :'ListInboxConversations200ResponseDataInnerInstagramProfile',
122
+ :'metadata' => :'ListInboxConversations200ResponseDataInnerMetadata'
119
123
  }
120
124
  end
121
125
 
@@ -200,6 +204,10 @@ module Zernio
200
204
  if attributes.key?(:'instagram_profile')
201
205
  self.instagram_profile = attributes[:'instagram_profile']
202
206
  end
207
+
208
+ if attributes.key?(:'metadata')
209
+ self.metadata = attributes[:'metadata']
210
+ end
203
211
  end
204
212
 
205
213
  # Show invalid properties with the reasons. Usually used together with valid?
@@ -259,7 +267,8 @@ module Zernio
259
267
  status == o.status &&
260
268
  unread_count == o.unread_count &&
261
269
  url == o.url &&
262
- instagram_profile == o.instagram_profile
270
+ instagram_profile == o.instagram_profile &&
271
+ metadata == o.metadata
263
272
  end
264
273
 
265
274
  # @see the `==` method
@@ -271,7 +280,7 @@ module Zernio
271
280
  # Calculates hash code according to all attributes.
272
281
  # @return [Integer] Hash code
273
282
  def hash
274
- [id, platform, account_id, account_username, participant_id, participant_name, participant_picture, participant_verified_type, last_message, updated_time, status, unread_count, url, instagram_profile].hash
283
+ [id, platform, account_id, account_username, participant_id, participant_name, participant_picture, participant_verified_type, last_message, updated_time, status, unread_count, url, instagram_profile, metadata].hash
275
284
  end
276
285
 
277
286
  # Builds the object from hash
@@ -0,0 +1,309 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api
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
+ # Ad-click attribution for a conversation that started from a Meta ad. Absent when the conversation did not originate from an ad click. Captured from the referral Meta attaches to the first inbound message after the click, which is the only message that carries it. If the same person later clicks a different ad, the original values are kept, so the first ad wins. One exception on WhatsApp: when Meta omits `ctwa_clid` from that referral, a later Meta automatic event can supply it and refresh `ctwa_captured_at`, so treat `ctwa_captured_at` as the time Zernio stored the value, not the time of the click. Two families of keys, one per surface. They never appear together: - `ctwa_*` is WhatsApp Click-to-WhatsApp. The ad ID is `ctwa_source_id`. There is no `meta_ad_id` on WhatsApp. - `meta_ad_*` is Instagram Click-to-Direct and Facebook Messenger Click-to-Message. The ad ID is `meta_ad_id`. `ctwa_clid` never appears on these platforms. Every key is optional and only the keys Meta supplied are returned, so read defensively. Meta does not send a campaign or ad set ID, so none is exposed here. More keys may be added over time. Treat any key you do not recognise as an opaque string. Key names differ from the `message.received` webhook on purpose. The webhook forwards Meta's referral verbatim (`ad_id`, `source`, `type`) while the stored conversation record uses the prefixed names below. Renaming either side would break existing integrations, so both spellings are kept.
18
+ class ListInboxConversations200ResponseDataInnerMetadata < ApiModelBase
19
+ # WhatsApp only. Meta's click identifier, the value to forward to the Meta Conversions API for Business Messaging. Meta omits it on some numbers, so a WhatsApp referral can arrive without it.
20
+ attr_accessor :ctwa_clid
21
+
22
+ # WhatsApp only. The Meta ad ID the user clicked. This is the WhatsApp equivalent of meta_ad_id.
23
+ attr_accessor :ctwa_source_id
24
+
25
+ # WhatsApp only. What the user clicked, as supplied by Meta (for example ad or post).
26
+ attr_accessor :ctwa_source_type
27
+
28
+ # WhatsApp only. Meta's URL for the ad that was clicked, normally an fb.me short link.
29
+ attr_accessor :ctwa_source_url
30
+
31
+ # WhatsApp only. Headline of the ad creative at click time.
32
+ attr_accessor :ctwa_headline
33
+
34
+ # WhatsApp only. When Zernio stored this referral. Always present when a WhatsApp referral was captured.
35
+ attr_accessor :ctwa_captured_at
36
+
37
+ # Instagram and Facebook only. The Meta ad ID the user clicked. Always present when an Instagram or Facebook referral was captured.
38
+ attr_accessor :meta_ad_id
39
+
40
+ # Instagram and Facebook only. Meta-supplied source identifier, for example ADS.
41
+ attr_accessor :meta_ad_source
42
+
43
+ # Instagram and Facebook only. Meta-supplied referral type, for example OPEN_THREAD.
44
+ attr_accessor :meta_ad_type
45
+
46
+ # Instagram and Facebook only. The ref parameter passed through from the ad creative.
47
+ attr_accessor :meta_ad_ref
48
+
49
+ # Instagram and Facebook only. Title of the ad creative at click time.
50
+ attr_accessor :meta_ad_title
51
+
52
+ # Instagram and Facebook only. Image of the ad creative at click time.
53
+ attr_accessor :meta_ad_photo_url
54
+
55
+ # Instagram and Facebook only. Video of the ad creative at click time.
56
+ attr_accessor :meta_ad_video_url
57
+
58
+ # Instagram and Facebook only. The organic post the ad promoted, when the ad was a boosted post.
59
+ attr_accessor :meta_ad_post_id
60
+
61
+ # Instagram and Facebook only. The catalogue product the user clicked, for product ads.
62
+ attr_accessor :meta_ad_product_id
63
+
64
+ # Instagram and Facebook only. The Meta flow the ad launched, for flow ads.
65
+ attr_accessor :meta_ad_flow_id
66
+
67
+ # Instagram and Facebook only. When Zernio stored this referral. Always present when an Instagram or Facebook referral was captured.
68
+ attr_accessor :meta_ad_captured_at
69
+
70
+ # Attribute mapping from ruby-style variable name to JSON key.
71
+ def self.attribute_map
72
+ {
73
+ :'ctwa_clid' => :'ctwa_clid',
74
+ :'ctwa_source_id' => :'ctwa_source_id',
75
+ :'ctwa_source_type' => :'ctwa_source_type',
76
+ :'ctwa_source_url' => :'ctwa_source_url',
77
+ :'ctwa_headline' => :'ctwa_headline',
78
+ :'ctwa_captured_at' => :'ctwa_captured_at',
79
+ :'meta_ad_id' => :'meta_ad_id',
80
+ :'meta_ad_source' => :'meta_ad_source',
81
+ :'meta_ad_type' => :'meta_ad_type',
82
+ :'meta_ad_ref' => :'meta_ad_ref',
83
+ :'meta_ad_title' => :'meta_ad_title',
84
+ :'meta_ad_photo_url' => :'meta_ad_photo_url',
85
+ :'meta_ad_video_url' => :'meta_ad_video_url',
86
+ :'meta_ad_post_id' => :'meta_ad_post_id',
87
+ :'meta_ad_product_id' => :'meta_ad_product_id',
88
+ :'meta_ad_flow_id' => :'meta_ad_flow_id',
89
+ :'meta_ad_captured_at' => :'meta_ad_captured_at'
90
+ }
91
+ end
92
+
93
+ # Returns attribute mapping this model knows about
94
+ def self.acceptable_attribute_map
95
+ attribute_map
96
+ end
97
+
98
+ # Returns all the JSON keys this model knows about
99
+ def self.acceptable_attributes
100
+ acceptable_attribute_map.values
101
+ end
102
+
103
+ # Attribute type mapping.
104
+ def self.openapi_types
105
+ {
106
+ :'ctwa_clid' => :'String',
107
+ :'ctwa_source_id' => :'String',
108
+ :'ctwa_source_type' => :'String',
109
+ :'ctwa_source_url' => :'String',
110
+ :'ctwa_headline' => :'String',
111
+ :'ctwa_captured_at' => :'Time',
112
+ :'meta_ad_id' => :'String',
113
+ :'meta_ad_source' => :'String',
114
+ :'meta_ad_type' => :'String',
115
+ :'meta_ad_ref' => :'String',
116
+ :'meta_ad_title' => :'String',
117
+ :'meta_ad_photo_url' => :'String',
118
+ :'meta_ad_video_url' => :'String',
119
+ :'meta_ad_post_id' => :'String',
120
+ :'meta_ad_product_id' => :'String',
121
+ :'meta_ad_flow_id' => :'String',
122
+ :'meta_ad_captured_at' => :'Time'
123
+ }
124
+ end
125
+
126
+ # List of attributes with nullable: true
127
+ def self.openapi_nullable
128
+ Set.new([
129
+ ])
130
+ end
131
+
132
+ # Initializes the object
133
+ # @param [Hash] attributes Model attributes in the form of hash
134
+ def initialize(attributes = {})
135
+ if (!attributes.is_a?(Hash))
136
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Zernio::ListInboxConversations200ResponseDataInnerMetadata` initialize method"
137
+ end
138
+
139
+ # check to see if the attribute exists and convert string to symbol for hash key
140
+ acceptable_attribute_map = self.class.acceptable_attribute_map
141
+ attributes = attributes.each_with_object({}) { |(k, v), h|
142
+ if (!acceptable_attribute_map.key?(k.to_sym))
143
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Zernio::ListInboxConversations200ResponseDataInnerMetadata`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
144
+ end
145
+ h[k.to_sym] = v
146
+ }
147
+
148
+ if attributes.key?(:'ctwa_clid')
149
+ self.ctwa_clid = attributes[:'ctwa_clid']
150
+ end
151
+
152
+ if attributes.key?(:'ctwa_source_id')
153
+ self.ctwa_source_id = attributes[:'ctwa_source_id']
154
+ end
155
+
156
+ if attributes.key?(:'ctwa_source_type')
157
+ self.ctwa_source_type = attributes[:'ctwa_source_type']
158
+ end
159
+
160
+ if attributes.key?(:'ctwa_source_url')
161
+ self.ctwa_source_url = attributes[:'ctwa_source_url']
162
+ end
163
+
164
+ if attributes.key?(:'ctwa_headline')
165
+ self.ctwa_headline = attributes[:'ctwa_headline']
166
+ end
167
+
168
+ if attributes.key?(:'ctwa_captured_at')
169
+ self.ctwa_captured_at = attributes[:'ctwa_captured_at']
170
+ end
171
+
172
+ if attributes.key?(:'meta_ad_id')
173
+ self.meta_ad_id = attributes[:'meta_ad_id']
174
+ end
175
+
176
+ if attributes.key?(:'meta_ad_source')
177
+ self.meta_ad_source = attributes[:'meta_ad_source']
178
+ end
179
+
180
+ if attributes.key?(:'meta_ad_type')
181
+ self.meta_ad_type = attributes[:'meta_ad_type']
182
+ end
183
+
184
+ if attributes.key?(:'meta_ad_ref')
185
+ self.meta_ad_ref = attributes[:'meta_ad_ref']
186
+ end
187
+
188
+ if attributes.key?(:'meta_ad_title')
189
+ self.meta_ad_title = attributes[:'meta_ad_title']
190
+ end
191
+
192
+ if attributes.key?(:'meta_ad_photo_url')
193
+ self.meta_ad_photo_url = attributes[:'meta_ad_photo_url']
194
+ end
195
+
196
+ if attributes.key?(:'meta_ad_video_url')
197
+ self.meta_ad_video_url = attributes[:'meta_ad_video_url']
198
+ end
199
+
200
+ if attributes.key?(:'meta_ad_post_id')
201
+ self.meta_ad_post_id = attributes[:'meta_ad_post_id']
202
+ end
203
+
204
+ if attributes.key?(:'meta_ad_product_id')
205
+ self.meta_ad_product_id = attributes[:'meta_ad_product_id']
206
+ end
207
+
208
+ if attributes.key?(:'meta_ad_flow_id')
209
+ self.meta_ad_flow_id = attributes[:'meta_ad_flow_id']
210
+ end
211
+
212
+ if attributes.key?(:'meta_ad_captured_at')
213
+ self.meta_ad_captured_at = attributes[:'meta_ad_captured_at']
214
+ end
215
+ end
216
+
217
+ # Show invalid properties with the reasons. Usually used together with valid?
218
+ # @return Array for valid properties with the reasons
219
+ def list_invalid_properties
220
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
221
+ invalid_properties = Array.new
222
+ invalid_properties
223
+ end
224
+
225
+ # Check to see if the all the properties in the model are valid
226
+ # @return true if the model is valid
227
+ def valid?
228
+ warn '[DEPRECATED] the `valid?` method is obsolete'
229
+ true
230
+ end
231
+
232
+ # Checks equality by comparing each attribute.
233
+ # @param [Object] Object to be compared
234
+ def ==(o)
235
+ return true if self.equal?(o)
236
+ self.class == o.class &&
237
+ ctwa_clid == o.ctwa_clid &&
238
+ ctwa_source_id == o.ctwa_source_id &&
239
+ ctwa_source_type == o.ctwa_source_type &&
240
+ ctwa_source_url == o.ctwa_source_url &&
241
+ ctwa_headline == o.ctwa_headline &&
242
+ ctwa_captured_at == o.ctwa_captured_at &&
243
+ meta_ad_id == o.meta_ad_id &&
244
+ meta_ad_source == o.meta_ad_source &&
245
+ meta_ad_type == o.meta_ad_type &&
246
+ meta_ad_ref == o.meta_ad_ref &&
247
+ meta_ad_title == o.meta_ad_title &&
248
+ meta_ad_photo_url == o.meta_ad_photo_url &&
249
+ meta_ad_video_url == o.meta_ad_video_url &&
250
+ meta_ad_post_id == o.meta_ad_post_id &&
251
+ meta_ad_product_id == o.meta_ad_product_id &&
252
+ meta_ad_flow_id == o.meta_ad_flow_id &&
253
+ meta_ad_captured_at == o.meta_ad_captured_at
254
+ end
255
+
256
+ # @see the `==` method
257
+ # @param [Object] Object to be compared
258
+ def eql?(o)
259
+ self == o
260
+ end
261
+
262
+ # Calculates hash code according to all attributes.
263
+ # @return [Integer] Hash code
264
+ def hash
265
+ [ctwa_clid, ctwa_source_id, ctwa_source_type, ctwa_source_url, ctwa_headline, ctwa_captured_at, meta_ad_id, meta_ad_source, meta_ad_type, meta_ad_ref, meta_ad_title, meta_ad_photo_url, meta_ad_video_url, meta_ad_post_id, meta_ad_product_id, meta_ad_flow_id, meta_ad_captured_at].hash
266
+ end
267
+
268
+ # Builds the object from hash
269
+ # @param [Hash] attributes Model attributes in the form of hash
270
+ # @return [Object] Returns the model itself
271
+ def self.build_from_hash(attributes)
272
+ return nil unless attributes.is_a?(Hash)
273
+ attributes = attributes.transform_keys(&:to_sym)
274
+ transformed_hash = {}
275
+ openapi_types.each_pair do |key, type|
276
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
277
+ transformed_hash["#{key}"] = nil
278
+ elsif type =~ /\AArray<(.*)>/i
279
+ # check to ensure the input is an array given that the attribute
280
+ # is documented as an array but the input is not
281
+ if attributes[attribute_map[key]].is_a?(Array)
282
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
283
+ end
284
+ elsif !attributes[attribute_map[key]].nil?
285
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
286
+ end
287
+ end
288
+ new(transformed_hash)
289
+ end
290
+
291
+ # Returns the object in the form of hash
292
+ # @return [Hash] Returns the object in the form of hash
293
+ def to_hash
294
+ hash = {}
295
+ self.class.attribute_map.each_pair do |attr, param|
296
+ value = self.send(attr)
297
+ if value.nil?
298
+ is_nullable = self.class.openapi_nullable.include?(attr)
299
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
300
+ end
301
+
302
+ hash[param] = _to_hash(value)
303
+ end
304
+ hash
305
+ end
306
+
307
+ end
308
+
309
+ end
@@ -11,5 +11,5 @@ Generator version: 7.19.0
11
11
  =end
12
12
 
13
13
  module Zernio
14
- VERSION = '0.0.644'
14
+ VERSION = '0.0.646'
15
15
  end
data/lib/zernio-sdk.rb CHANGED
@@ -551,6 +551,7 @@ require 'zernio-sdk/models/get_google_business_verifications200_response_voice_o
551
551
  require 'zernio-sdk/models/get_google_business_verifications200_response_voice_of_merchant_state_verify'
552
552
  require 'zernio-sdk/models/get_inbox_conversation200_response'
553
553
  require 'zernio-sdk/models/get_inbox_conversation200_response_data'
554
+ require 'zernio-sdk/models/get_inbox_conversation200_response_data_metadata'
554
555
  require 'zernio-sdk/models/get_inbox_conversation_analytics200_response'
555
556
  require 'zernio-sdk/models/get_inbox_conversation_analytics200_response_by_source_inner'
556
557
  require 'zernio-sdk/models/get_inbox_conversation_analytics200_response_summary'
@@ -873,6 +874,7 @@ require 'zernio-sdk/models/list_inbox_conversation_analytics200_response_paginat
873
874
  require 'zernio-sdk/models/list_inbox_conversations200_response'
874
875
  require 'zernio-sdk/models/list_inbox_conversations200_response_data_inner'
875
876
  require 'zernio-sdk/models/list_inbox_conversations200_response_data_inner_instagram_profile'
877
+ require 'zernio-sdk/models/list_inbox_conversations200_response_data_inner_metadata'
876
878
  require 'zernio-sdk/models/list_inbox_conversations200_response_meta'
877
879
  require 'zernio-sdk/models/list_inbox_conversations200_response_meta_failed_accounts_inner'
878
880
  require 'zernio-sdk/models/list_inbox_conversations200_response_pagination'
data/openapi.yaml CHANGED
@@ -6562,7 +6562,9 @@ components:
6562
6562
  properties:
6563
6563
  spend: { type: number }
6564
6564
  impressions: { type: integer }
6565
- reach: { type: integer }
6565
+ reach:
6566
+ type: integer
6567
+ description: "Unique people reached in the requested date range. Meta (facebook/instagram): Meta's own de-duplicated reach for the exact range, fetched live and cached up to ~1 hour (may lag recent delivery; on a transient Meta error the value temporarily falls back to a sum of per-day reach, which overcounts people reached on multiple days or by multiple child ads). Because it is de-duplicated, Meta reach is NOT additive: neither daily values nor child nodes sum to the range total. TikTok: sum of per-day reach, so multi-day ranges overcount vs TikTok Ads Manager. Google, LinkedIn, X, Pinterest and OpenAI report 0 (reach not synced). Only derive frequency (impressions / reach) for Meta."
6566
6568
  clicks: { type: integer }
6567
6569
  ctr: { type: number, description: Click-through rate (%) }
6568
6570
  cpc: { type: number, description: Cost per click }
@@ -6618,7 +6620,9 @@ components:
6618
6620
  called with `timeIncrement=1`. Rate metrics (ctr/cpc/cpm/costPerConversion/
6619
6621
  roas/videoAvgTimeWatchedActions) are recomputed per day from that day's
6620
6622
  sums, so summing the additive fields across a node's `daily[]` reproduces
6621
- its aggregated `metrics` total. Do NOT sum or plain-average
6623
+ its aggregated `metrics` total. `reach` is the exception: on Meta the
6624
+ aggregated total is de-duplicated across the range, so daily reach does
6625
+ not sum to it. Do NOT sum or plain-average
6622
6626
  `videoAvgTimeWatchedActions` across days: the range value is the
6623
6627
  play-weighted average of the daily values.
6624
6628
  allOf:
@@ -7177,7 +7181,7 @@ components:
7177
7181
  daily:
7178
7182
  type: array
7179
7183
  items: { $ref: '#/components/schemas/AdDailyMetrics' }
7180
- description: "Per-day metric series for this campaign. Present only when `GET /v1/ads/tree` is called with `timeIncrement=1` (any `dailyLevel`). This is the per-campaign daily trend — summing its additive fields reproduces the campaign `metrics` total."
7184
+ description: "Per-day metric series for this campaign. Present only when `GET /v1/ads/tree` is called with `timeIncrement=1` (any `dailyLevel`). This is the per-campaign daily trend — summing its additive fields reproduces the campaign `metrics` total, except `reach`: on Meta the range total is de-duplicated, so daily reach does not sum to it."
7181
7185
  AdCampaign:
7182
7186
  type: object
7183
7187
  properties:
@@ -22563,7 +22567,7 @@ paths:
22563
22567
  description: Filter by profile ID
22564
22568
  - name: platform
22565
22569
  in: query
22566
- schema: { type: string, enum: [facebook, instagram, twitter, bluesky, reddit, telegram] }
22570
+ schema: { type: string, enum: [facebook, instagram, twitter, bluesky, reddit, telegram, whatsapp] }
22567
22571
  description: Filter by platform
22568
22572
  - name: status
22569
22573
  in: query
@@ -22638,6 +22642,92 @@ paths:
22638
22642
  type: [string, "null"]
22639
22643
  format: date-time
22640
22644
  description: When this profile data was last fetched from Instagram
22645
+ metadata:
22646
+ type: [object, "null"]
22647
+ description: |
22648
+ Ad-click attribution for a conversation that started from a Meta ad.
22649
+ Absent when the conversation did not originate from an ad click.
22650
+
22651
+ Captured from the referral Meta attaches to the first inbound message
22652
+ after the click, which is the only message that carries it. If the same
22653
+ person later clicks a different ad, the original values are kept, so the
22654
+ first ad wins. One exception on WhatsApp: when Meta omits `ctwa_clid`
22655
+ from that referral, a later Meta automatic event can supply it and
22656
+ refresh `ctwa_captured_at`, so treat `ctwa_captured_at` as the time
22657
+ Zernio stored the value, not the time of the click.
22658
+
22659
+ Two families of keys, one per surface. They never appear together:
22660
+
22661
+ - `ctwa_*` is WhatsApp Click-to-WhatsApp. The ad ID is
22662
+ `ctwa_source_id`. There is no `meta_ad_id` on WhatsApp.
22663
+ - `meta_ad_*` is Instagram Click-to-Direct and Facebook Messenger
22664
+ Click-to-Message. The ad ID is `meta_ad_id`. `ctwa_clid` never
22665
+ appears on these platforms.
22666
+
22667
+ Every key is optional and only the keys Meta supplied are returned, so
22668
+ read defensively. Meta does not send a campaign or ad set ID, so none
22669
+ is exposed here. More keys may be added over time. Treat any key you
22670
+ do not recognise as an opaque string.
22671
+
22672
+ Key names differ from the `message.received` webhook on purpose. The
22673
+ webhook forwards Meta's referral verbatim (`ad_id`, `source`, `type`)
22674
+ while the stored conversation record uses the prefixed names below.
22675
+ Renaming either side would break existing integrations, so both
22676
+ spellings are kept.
22677
+ properties:
22678
+ ctwa_clid:
22679
+ type: string
22680
+ description: "WhatsApp only. Meta's click identifier, the value to forward to the Meta Conversions API for Business Messaging. Meta omits it on some numbers, so a WhatsApp referral can arrive without it."
22681
+ ctwa_source_id:
22682
+ type: string
22683
+ description: "WhatsApp only. The Meta ad ID the user clicked. This is the WhatsApp equivalent of meta_ad_id."
22684
+ ctwa_source_type:
22685
+ type: string
22686
+ description: "WhatsApp only. What the user clicked, as supplied by Meta (for example ad or post)."
22687
+ ctwa_source_url:
22688
+ type: string
22689
+ description: "WhatsApp only. Meta's URL for the ad that was clicked, normally an fb.me short link."
22690
+ ctwa_headline:
22691
+ type: string
22692
+ description: "WhatsApp only. Headline of the ad creative at click time."
22693
+ ctwa_captured_at:
22694
+ type: string
22695
+ format: date-time
22696
+ description: "WhatsApp only. When Zernio stored this referral. Always present when a WhatsApp referral was captured."
22697
+ meta_ad_id:
22698
+ type: string
22699
+ description: "Instagram and Facebook only. The Meta ad ID the user clicked. Always present when an Instagram or Facebook referral was captured."
22700
+ meta_ad_source:
22701
+ type: string
22702
+ description: "Instagram and Facebook only. Meta-supplied source identifier, for example ADS."
22703
+ meta_ad_type:
22704
+ type: string
22705
+ description: "Instagram and Facebook only. Meta-supplied referral type, for example OPEN_THREAD."
22706
+ meta_ad_ref:
22707
+ type: string
22708
+ description: "Instagram and Facebook only. The ref parameter passed through from the ad creative."
22709
+ meta_ad_title:
22710
+ type: string
22711
+ description: "Instagram and Facebook only. Title of the ad creative at click time."
22712
+ meta_ad_photo_url:
22713
+ type: string
22714
+ description: "Instagram and Facebook only. Image of the ad creative at click time."
22715
+ meta_ad_video_url:
22716
+ type: string
22717
+ description: "Instagram and Facebook only. Video of the ad creative at click time."
22718
+ meta_ad_post_id:
22719
+ type: string
22720
+ description: "Instagram and Facebook only. The organic post the ad promoted, when the ad was a boosted post."
22721
+ meta_ad_product_id:
22722
+ type: string
22723
+ description: "Instagram and Facebook only. The catalogue product the user clicked, for product ads."
22724
+ meta_ad_flow_id:
22725
+ type: string
22726
+ description: "Instagram and Facebook only. The Meta flow the ad launched, for flow ads."
22727
+ meta_ad_captured_at:
22728
+ type: string
22729
+ format: date-time
22730
+ description: "Instagram and Facebook only. When Zernio stored this referral. Always present when an Instagram or Facebook referral was captured."
22641
22731
  pagination:
22642
22732
  type: object
22643
22733
  properties:
@@ -23024,6 +23114,68 @@ paths:
23024
23114
  type: [string, "null"]
23025
23115
  format: date-time
23026
23116
  description: When this profile data was last fetched from Instagram
23117
+ metadata:
23118
+ type: [object, "null"]
23119
+ description: |
23120
+ Ad-click attribution for a conversation that started from a Meta ad.
23121
+ Absent when the conversation did not originate from an ad click.
23122
+
23123
+ Captured once, on the first inbound message after the click, and never
23124
+ overwritten. If the same person later clicks a different ad, the
23125
+ original values are kept. Meta only sends the referral on that first
23126
+ message.
23127
+
23128
+ This operation currently returns only the `meta_ad_*` family, which
23129
+ covers Instagram Click-to-Direct and Facebook Messenger
23130
+ Click-to-Message. WhatsApp Click-to-WhatsApp attribution (the `ctwa_*`
23131
+ keys, where the ad ID is `ctwa_source_id`) is returned by
23132
+ `GET /v1/inbox/conversations` instead.
23133
+
23134
+ Every key is optional and only the keys Meta supplied are returned, so
23135
+ read defensively. Meta does not send a campaign or ad set ID, so none is
23136
+ exposed here. More keys may be added over time. Treat any key you do not
23137
+ recognise as an opaque string.
23138
+
23139
+ Key names differ from the `message.received` webhook on purpose. The
23140
+ webhook forwards Meta's referral verbatim (`ad_id`, `source`, `type`)
23141
+ while the stored conversation record uses the prefixed names below.
23142
+ Renaming either side would break existing integrations, so both
23143
+ spellings are kept.
23144
+ properties:
23145
+ meta_ad_id:
23146
+ type: string
23147
+ description: "The Meta ad ID the user clicked. Always present when a referral was captured."
23148
+ meta_ad_source:
23149
+ type: string
23150
+ description: "Meta-supplied source identifier, for example ADS."
23151
+ meta_ad_type:
23152
+ type: string
23153
+ description: "Meta-supplied referral type, for example OPEN_THREAD."
23154
+ meta_ad_ref:
23155
+ type: string
23156
+ description: "The ref parameter passed through from the ad creative."
23157
+ meta_ad_title:
23158
+ type: string
23159
+ description: "Title of the ad creative at click time."
23160
+ meta_ad_photo_url:
23161
+ type: string
23162
+ description: "Image of the ad creative at click time."
23163
+ meta_ad_video_url:
23164
+ type: string
23165
+ description: "Video of the ad creative at click time."
23166
+ meta_ad_post_id:
23167
+ type: string
23168
+ description: "The organic post the ad promoted, when the ad was a boosted post."
23169
+ meta_ad_product_id:
23170
+ type: string
23171
+ description: "The catalogue product the user clicked, for product ads."
23172
+ meta_ad_flow_id:
23173
+ type: string
23174
+ description: "The Meta flow the ad launched, for flow ads."
23175
+ meta_ad_captured_at:
23176
+ type: string
23177
+ format: date-time
23178
+ description: "When Zernio stored this referral. Always present when a referral was captured."
23027
23179
  '401': { $ref: '#/components/responses/Unauthorized' }
23028
23180
  '403':
23029
23181
  description: Inbox addon required
@@ -35773,7 +35925,7 @@ paths:
35773
35925
  - { name: fromDate, in: query, schema: { type: string, format: date }, description: "Start of the METRICS date range (YYYY-MM-DD). Affects only the spend/impression numbers overlaid on each node, NOT which campaigns are returned. Defaults to 90 days ago." }
35774
35926
  - { name: toDate, in: query, schema: { type: string, format: date }, description: "End of metrics date range (YYYY-MM-DD). Defaults to today. Max 730-day range." }
35775
35927
  - { name: sort, in: query, schema: { type: string, enum: [newest, oldest, spend_desc, spend_asc], default: newest }, description: "Campaign-level sort order. `newest` (default) / `oldest` order by the campaign's newest-ad createdAt. `spend_desc` / `spend_asc` order by aggregated spend in the requested date range; campaigns with no spend land at the end." }
35776
- - { name: timeIncrement, in: query, schema: { type: integer, enum: [1] }, description: "Set to `1` to also return a daily breakdown. Mirrors Meta Insights' `time_increment=1`: each node gains a `daily[]` array of per-day metrics (same fields as the aggregated `metrics`) alongside the range total, so you get per-entity daily trends in ONE call instead of calling the tree once per day. Only `1` (daily) is supported. The daily series covers the same date range and uses the same source data as `metrics`. See `dailyLevel` to control which levels carry it." }
35928
+ - { name: timeIncrement, in: query, schema: { type: integer, enum: [1] }, description: "Set to `1` to also return a daily breakdown. Mirrors Meta Insights' `time_increment=1`: each node gains a `daily[]` array of per-day metrics (same fields as the aggregated `metrics`) alongside the range total, so you get per-entity daily trends in ONE call instead of calling the tree once per day. Only `1` (daily) is supported. The daily series covers the same date range and uses the same source data as `metrics`, except Meta `reach`: the range total is Meta's de-duplicated value, so daily reach does not sum to it. See `dailyLevel` to control which levels carry it." }
35777
35929
  - { name: dailyLevel, in: query, schema: { type: string, enum: [campaign, adset, ad], default: campaign }, description: "Which tree levels get the `daily[]` series when `timeIncrement=1`. `campaign` (default) attaches it on campaign nodes only — the common per-campaign-trend case, and the smallest payload. `adset` adds it on ad sets too; `ad` adds it on every ad in `ads[]` as well (heaviest — a long range × up to 100 ads per ad set). Scope with `campaignId` to keep `ad`-level responses small. Ignored when `timeIncrement` is unset." }
35778
35930
  responses:
35779
35931
  '200':
@@ -35840,7 +35992,7 @@ paths:
35840
35992
  date: { type: string, format: date }
35841
35993
  spend: { type: number, description: "Native currency units (matches /ads/tree convention)." }
35842
35994
  impressions: { type: integer }
35843
- reach: { type: integer }
35995
+ reach: { type: integer, description: "Reach summed across the account's ads for this single day. A person seen by two ads the same day counts twice, and reach is de-duplicated per day only: do NOT sum it across days (people reached on multiple days would be double-counted)." }
35844
35996
  clicks: { type: integer }
35845
35997
  engagement: { type: integer }
35846
35998
  ctr: { type: number, description: "Click-through rate as a percentage (0–100)." }
@@ -192,7 +192,7 @@ describe 'AdCampaignsApi' do
192
192
  # @option opts [Date] :from_date Start of the METRICS date range (YYYY-MM-DD). Affects only the spend/impression numbers overlaid on each node, NOT which campaigns are returned. Defaults to 90 days ago.
193
193
  # @option opts [Date] :to_date End of metrics date range (YYYY-MM-DD). Defaults to today. Max 730-day range.
194
194
  # @option opts [String] :sort Campaign-level sort order. &#x60;newest&#x60; (default) / &#x60;oldest&#x60; order by the campaign&#39;s newest-ad createdAt. &#x60;spend_desc&#x60; / &#x60;spend_asc&#x60; order by aggregated spend in the requested date range; campaigns with no spend land at the end.
195
- # @option opts [Integer] :time_increment Set to &#x60;1&#x60; to also return a daily breakdown. Mirrors Meta Insights&#39; &#x60;time_increment&#x3D;1&#x60;: each node gains a &#x60;daily[]&#x60; array of per-day metrics (same fields as the aggregated &#x60;metrics&#x60;) alongside the range total, so you get per-entity daily trends in ONE call instead of calling the tree once per day. Only &#x60;1&#x60; (daily) is supported. The daily series covers the same date range and uses the same source data as &#x60;metrics&#x60;. See &#x60;dailyLevel&#x60; to control which levels carry it.
195
+ # @option opts [Integer] :time_increment Set to &#x60;1&#x60; to also return a daily breakdown. Mirrors Meta Insights&#39; &#x60;time_increment&#x3D;1&#x60;: each node gains a &#x60;daily[]&#x60; array of per-day metrics (same fields as the aggregated &#x60;metrics&#x60;) alongside the range total, so you get per-entity daily trends in ONE call instead of calling the tree once per day. Only &#x60;1&#x60; (daily) is supported. The daily series covers the same date range and uses the same source data as &#x60;metrics&#x60;, except Meta &#x60;reach&#x60;: the range total is Meta&#39;s de-duplicated value, so daily reach does not sum to it. See &#x60;dailyLevel&#x60; to control which levels carry it.
196
196
  # @option opts [String] :daily_level Which tree levels get the &#x60;daily[]&#x60; series when &#x60;timeIncrement&#x3D;1&#x60;. &#x60;campaign&#x60; (default) attaches it on campaign nodes only — the common per-campaign-trend case, and the smallest payload. &#x60;adset&#x60; adds it on ad sets too; &#x60;ad&#x60; adds it on every ad in &#x60;ads[]&#x60; as well (heaviest — a long range × up to 100 ads per ad set). Scope with &#x60;campaignId&#x60; to keep &#x60;ad&#x60;-level responses small. Ignored when &#x60;timeIncrement&#x60; is unset.
197
197
  # @return [GetAdTree200Response]
198
198
  describe 'get_ad_tree test' do