fopost 0.2.0 → 0.3.0

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.
data/lib/fopost/models.rb CHANGED
@@ -4,12 +4,44 @@ require 'fopost/model'
4
4
 
5
5
  module Fopost
6
6
  class MediaItem < Model
7
+ attribute :id
7
8
  attribute :type
8
9
  attribute :name
9
10
  attribute :url
10
11
  attribute :size
11
12
  attribute :alt
12
13
  attribute :thumbnail
14
+ attribute :preview_url
15
+ end
16
+
17
+ # Where and how to PUT the bytes of a direct upload.
18
+ class PresignedUpload < Model
19
+ attribute :upload_id
20
+ attribute :upload_url
21
+ attribute :method
22
+ attribute :headers, :hash
23
+ attribute :expires_at, :time
24
+ attribute :max_file_bytes
25
+ end
26
+
27
+ # The next connected-accounts tier and the ceiling it unlocks.
28
+ class UploadLimitTier < Model
29
+ attribute :up_to_accounts
30
+ attribute :max_file_bytes
31
+ end
32
+
33
+ # What the workspace may upload: the ceiling by any route, the multipart
34
+ # ceiling per file, and how many files one request takes.
35
+ class UploadLimits < Model
36
+ attribute :max_file_bytes
37
+ attribute :source
38
+ attribute :connected_accounts
39
+ attribute :large_uploads_enabled
40
+ attribute :next_tier, UploadLimitTier
41
+ attribute :multipart_max_file_bytes
42
+ attribute :max_files_per_upload
43
+ attribute :direct_upload_available
44
+ attribute :allowed_types
13
45
  end
14
46
 
15
47
  # One block of a post. A thread is several blocks in order.
@@ -32,6 +64,487 @@ module Fopost
32
64
  attribute :is_primary
33
65
  attribute :health_status
34
66
  attribute :last_health_check, :time
67
+ attribute :platform_name
68
+ # True when the account was connected before a permission it now needs was asked for.
69
+ attribute :reconnect_required
70
+ end
71
+
72
+ # The result of renaming an account; `name` is the override when set, else the platform name.
73
+ class AccountRename < Model
74
+ attribute :id
75
+ attribute :name
76
+ attribute :platform_name
77
+ end
78
+
79
+ # The result of moving an account to another workspace.
80
+ class AccountMove < Model
81
+ attribute :id
82
+ attribute :workspace_id
83
+ end
84
+
85
+ # A one-time code that connects a Telegram chat; send `command` to the bot there.
86
+ class TelegramConnectCode < Model
87
+ attribute :code
88
+ attribute :command
89
+ attribute :bot_username
90
+ attribute :deep_link
91
+ attribute :group_link
92
+ attribute :expires_at, :time
93
+ end
94
+
95
+ # Where a connect code stands: `pending`, `connected`, `failed` or `expired`.
96
+ class TelegramConnectStatus < Model
97
+ attribute :status
98
+ attribute :account_id
99
+ attribute :reason
100
+ end
101
+
102
+ # One entry in the bot's command menu.
103
+ class TelegramBotCommand < Model
104
+ attribute :command
105
+ attribute :description
106
+ end
107
+
108
+ # The command menu the bot shows in a connected chat.
109
+ class TelegramBotCommands < Model
110
+ attribute :commands, [TelegramBotCommand]
111
+ end
112
+
113
+ # A tappable prompt Messenger or Instagram shows before the first message.
114
+ class MetaIceBreaker < Model
115
+ attribute :question
116
+ attribute :payload
117
+ end
118
+
119
+ # The ice breakers set on one account.
120
+ class MetaIceBreakers < Model
121
+ attribute :ice_breakers, [MetaIceBreaker]
122
+ end
123
+
124
+ # A menu item: a `postback` with a payload, or a `web_url` with a link.
125
+ class MetaMenuItem < Model
126
+ attribute :type
127
+ attribute :title
128
+ attribute :payload
129
+ attribute :url
130
+ end
131
+
132
+ # One locale's menu; `default` is the fallback every language uses.
133
+ class MetaPersistentMenuEntry < Model
134
+ attribute :locale
135
+ attribute :call_to_actions, [MetaMenuItem]
136
+ attribute :composer_input_disabled
137
+ end
138
+
139
+ # The persistent menu set on one account, one entry per locale.
140
+ class MetaPersistentMenu < Model
141
+ attribute :persistent_menu, [MetaPersistentMenuEntry]
142
+ end
143
+
144
+ # One locale's greeting, up to 160 characters.
145
+ class MetaGreetingText < Model
146
+ attribute :locale
147
+ attribute :text
148
+ end
149
+
150
+ # The greeting set on one account, one entry per locale.
151
+ class MetaGreeting < Model
152
+ attribute :greeting, [MetaGreetingText]
153
+ end
154
+
155
+ # What the network delivers to the FoPost webhook for one account.
156
+ class WebhookSubscription < Model
157
+ attribute :subscribed
158
+ attribute :fields
159
+ attribute :missing_fields
160
+ end
161
+
162
+ # The outcome of a Messenger thread hand-over; `app_id` is nil when control was taken back.
163
+ class InboxHandover < Model
164
+ attribute :app_id
165
+ attribute :control
166
+ end
167
+
168
+ # A Pinterest board; `id` travels as the `board_id` platform setting to pin to it.
169
+ class PinterestBoard < Model
170
+ attribute :id
171
+ attribute :name
172
+ attribute :privacy
173
+ attribute :description
174
+ attribute :image
175
+ end
176
+
177
+ # A playlist on the channel; `is_default` marks the one a new video joins by default.
178
+ class YouTubePlaylist < Model
179
+ attribute :id
180
+ attribute :title
181
+ attribute :description
182
+ attribute :privacy
183
+ attribute :item_count
184
+ attribute :thumbnail_url
185
+ attribute :is_default
186
+ end
187
+
188
+ # A caption track on one of the channel's videos.
189
+ class YouTubeCaptionTrack < Model
190
+ attribute :id
191
+ attribute :language
192
+ attribute :name
193
+ attribute :track_kind
194
+ attribute :is_draft
195
+ attribute :is_auto_synced
196
+ attribute :last_updated
197
+ end
198
+
199
+ # One caption track read back as text; `transcript` is SRT.
200
+ class YouTubeTranscript < Model
201
+ attribute :caption_id
202
+ attribute :transcript
203
+ end
204
+
205
+ # The default post languages for a connection; up to three BCP-47 tags.
206
+ class BlueskyLanguages < Model
207
+ attribute :languages
208
+ end
209
+
210
+ # The switches TikTok enforces at publish time, set on the account itself.
211
+ class TikTokCreatorInfo < Model
212
+ attribute :username
213
+ attribute :nickname
214
+ attribute :avatar_url
215
+ attribute :privacy_level_options
216
+ attribute :comment_disabled
217
+ attribute :duet_disabled
218
+ attribute :stitch_disabled
219
+ attribute :max_video_post_duration_sec
220
+ end
221
+
222
+ # A track from TikTok's Commercial Music Library; `id` travels as the
223
+ # `music_id` platform setting.
224
+ class TikTokMusic < Model
225
+ attribute :id
226
+ attribute :title
227
+ attribute :author
228
+ attribute :duration_sec
229
+ attribute :cover_url
230
+ attribute :preview_url
231
+ end
232
+
233
+ # A place a post can be tagged with; `id` travels as the `location_id`
234
+ # platform setting.
235
+ class TikTokPlace < Model
236
+ attribute :id
237
+ attribute :name
238
+ attribute :address
239
+ attribute :city
240
+ attribute :country
241
+ end
242
+
243
+ # One of the account's own videos, resolved from a share link. TikTok serves
244
+ # no raw media file, so `download_url` is the share address.
245
+ class TikTokVideoSource < Model
246
+ attribute :video_id
247
+ attribute :title
248
+ attribute :description
249
+ attribute :duration_sec
250
+ attribute :cover_image_url
251
+ attribute :share_url
252
+ attribute :embed_link
253
+ attribute :download_url
254
+ end
255
+
256
+ # A track a Reel can carry; `id` travels as the `audio_id` platform setting.
257
+ class InstagramAudio < Model
258
+ attribute :id
259
+ attribute :title
260
+ attribute :artist
261
+ attribute :duration_ms
262
+ attribute :audio_type
263
+ attribute :cover_artwork_url
264
+ attribute :preview_url
265
+ attribute :username
266
+ attribute :is_ads_eligible
267
+ end
268
+
269
+ # What this account has published in the rolling window, and what is left.
270
+ class InstagramPublishingLimit < Model
271
+ attribute :quota_usage
272
+ attribute :quota_total
273
+ attribute :quota_duration_sec
274
+ attribute :remaining
275
+ end
276
+
277
+ # A story still inside its 24 hours; `insights` is present only when asked for.
278
+ class InstagramStory < Model
279
+ attribute :id
280
+ attribute :media_type
281
+ attribute :media_product_type
282
+ attribute :permalink
283
+ attribute :media_url
284
+ attribute :thumbnail_url
285
+ attribute :caption
286
+ attribute :timestamp
287
+ attribute :insights
288
+ end
289
+
290
+ # Insights for one story.
291
+ class InstagramStoryInsights < Model
292
+ attribute :story_id
293
+ attribute :insights
294
+ end
295
+
296
+ # An entity a post can mention; `annotation` is what the post text carries.
297
+ class LinkedInMention < Model
298
+ attribute :urn
299
+ attribute :name
300
+ attribute :vanity_name
301
+ attribute :logo_url
302
+ attribute :type
303
+ attribute :annotation
304
+ end
305
+
306
+ # A channel the Slack app can post to; `is_current` marks the one this account posts to.
307
+ # A blog on a connected site. `id` is the platform's own id, never a FoPost
308
+ # one. Shopify reports every blog on the store; WordPress has one implicit
309
+ # blog and reports it under the id `default`, so both answer the same shape.
310
+ class RemoteBlog < Model
311
+ attribute :id
312
+ attribute :title
313
+ attribute :handle
314
+ attribute :url
315
+ end
316
+
317
+ # An article that already lives on a connected site.
318
+ class RemoteArticle < Model
319
+ attribute :id
320
+ attribute :blog_id
321
+ attribute :title
322
+ attribute :body_html
323
+ attribute :excerpt
324
+ # published, draft, pending or scheduled.
325
+ attribute :status
326
+ attribute :author_name
327
+ attribute :tags
328
+ attribute :image_url
329
+ attribute :url
330
+ attribute :published_at, :time
331
+ attribute :updated_at, :time
332
+ end
333
+
334
+ # A product on a connected store. `price` is the lowest variant price.
335
+ class RemoteProduct < Model
336
+ attribute :id
337
+ attribute :title
338
+ attribute :handle
339
+ # active, draft or archived.
340
+ attribute :status
341
+ attribute :description
342
+ attribute :vendor
343
+ attribute :product_type
344
+ attribute :tags
345
+ attribute :image_url
346
+ attribute :url
347
+ attribute :price
348
+ attribute :currency
349
+ attribute :updated_at, :time
350
+ end
351
+
352
+ class SlackChannel < Model
353
+ attribute :id
354
+ attribute :name
355
+ attribute :is_private
356
+ attribute :is_member
357
+ attribute :is_current
358
+ end
359
+
360
+ # A person in the connected Slack workspace; `id` is the handle for starting a DM.
361
+ class SlackMember < Model
362
+ attribute :id
363
+ attribute :name
364
+ attribute :real_name
365
+ attribute :display_name
366
+ attribute :avatar
367
+ attribute :is_bot
368
+ end
369
+
370
+ # The name and icon a Slack account posts under; nil means the app default.
371
+ class SlackIdentity < Model
372
+ attribute :username
373
+ attribute :icon_url
374
+ attribute :icon_emoji
375
+ end
376
+
377
+ # A Discord text channel the bot can post to; `is_current` marks this account's.
378
+ class DiscordChannel < Model
379
+ attribute :id
380
+ attribute :name
381
+ # Discord's channel type: 0 text, 5 announcement, 15 forum.
382
+ attribute :type
383
+ attribute :parent_id
384
+ attribute :nsfw
385
+ # False when a channel permission in Discord shuts the bot out.
386
+ attribute :can_post
387
+ attribute :is_current
388
+ end
389
+
390
+ # The nickname and avatar the bot wears in the server; nil means its own.
391
+ class DiscordIdentity < Model
392
+ attribute :username
393
+ attribute :avatar_url
394
+ end
395
+
396
+ # A message in the connected channel.
397
+ class DiscordMessage < Model
398
+ attribute :id
399
+ attribute :channel_id
400
+ attribute :content
401
+ attribute :author_id
402
+ attribute :author_name
403
+ attribute :pinned
404
+ attribute :created_at
405
+ end
406
+
407
+ # A message the bot put somewhere.
408
+ class DiscordMessageRef < Model
409
+ attribute :id
410
+ attribute :channel_id
411
+ end
412
+
413
+ # A thread started on a message.
414
+ class DiscordThread < Model
415
+ attribute :id
416
+ attribute :name
417
+ attribute :parent_id
418
+ end
419
+
420
+ # An event on the server's calendar; `channel_id` is a voice or stage channel,
421
+ # otherwise `location` says where it happens.
422
+ class DiscordScheduledEvent < Model
423
+ attribute :id
424
+ attribute :name
425
+ attribute :description
426
+ attribute :channel_id
427
+ attribute :location
428
+ attribute :start_time
429
+ attribute :end_time
430
+ # One of scheduled, active, completed, canceled.
431
+ attribute :status
432
+ attribute :user_count
433
+ end
434
+
435
+ # A person in the connected server; `id` is the member id for a DM or a role.
436
+ class DiscordMember < Model
437
+ attribute :id
438
+ attribute :username
439
+ attribute :display_name
440
+ attribute :nick
441
+ attribute :avatar
442
+ attribute :is_bot
443
+ attribute :roles
444
+ attribute :joined_at
445
+ end
446
+
447
+ # A role in the connected server; `permissions` is Discord's bitfield as a decimal string.
448
+ class DiscordRole < Model
449
+ attribute :id
450
+ attribute :name
451
+ attribute :color
452
+ attribute :hoist
453
+ attribute :mentionable
454
+ # A managed role belongs to an integration and cannot be edited.
455
+ attribute :managed
456
+ attribute :position
457
+ attribute :permissions
458
+ end
459
+
460
+ # One metric a network reports under its own name. `key` is the platform's own
461
+ # name and is stable; `label` is ours and may be reworded. `value` is a number
462
+ # for every kind but `series`, which is an array of points.
463
+ class PlatformMetricRow < Model
464
+ attribute :key
465
+ attribute :label
466
+ attribute :kind
467
+ attribute :value
468
+ end
469
+
470
+ # One side of a per-network metric set: the account itself, or its newest
471
+ # measured post. `external_post_id` is nil on the account side.
472
+ class PlatformMetricsBlock < Model
473
+ attribute :fetched_at
474
+ attribute :external_post_id
475
+ attribute :metrics, [PlatformMetricRow]
476
+ end
477
+
478
+ # What only this network reports, in its own vocabulary.
479
+ class AccountPlatformMetrics < Model
480
+ attribute :platform
481
+ attribute :account, PlatformMetricsBlock
482
+ attribute :post, PlatformMetricsBlock
483
+ end
484
+
485
+ # A subreddit the account is in, or its own profile page. `can_post` is false
486
+ # where it may read but not submit.
487
+ class RedditSubreddit < Model
488
+ attribute :name
489
+ attribute :title
490
+ attribute :subscribers
491
+ attribute :over18
492
+ attribute :can_post
493
+ attribute :flair_enabled
494
+ attribute :icon_url
495
+ attribute :is_default
496
+ end
497
+
498
+ # One rule a subreddit publishes; `applies_to` is 'link', 'comment' or 'all'.
499
+ class RedditSubredditRule < Model
500
+ attribute :name
501
+ attribute :description
502
+ attribute :applies_to
503
+ end
504
+
505
+ # The rules a subreddit publishes, in its own order.
506
+ class RedditSubredditRules < Model
507
+ attribute :subreddit
508
+ attribute :rules, [RedditSubredditRule]
509
+ end
510
+
511
+ # A post flair, valid only in the subreddit it came from.
512
+ class RedditFlair < Model
513
+ attribute :id
514
+ attribute :text
515
+ # Whether the label may be replaced with your own text.
516
+ attribute :editable
517
+ end
518
+
519
+ # Post flairs one subreddit offers.
520
+ class RedditFlairs < Model
521
+ attribute :subreddit
522
+ attribute :flairs, [RedditFlair]
523
+ end
524
+
525
+ # Where posts go when a post names none; nil means the account's own profile page.
526
+ class RedditDefaultSubreddit < Model
527
+ attribute :subreddit
528
+ end
529
+
530
+ # `ok` is true when the subreddit exists and takes a post from this account.
531
+ class SubredditCheck < Model
532
+ attribute :subreddit
533
+ attribute :exists
534
+ attribute :can_post
535
+ # The API field is over_18.
536
+ attribute :over_18 # rubocop:disable Naming/VariableNumber
537
+ attribute :flair_enabled
538
+ attribute :ok
539
+ end
540
+
541
+ # A named set of connected accounts in one workspace.
542
+ class AccountGroup < Model
543
+ attribute :id
544
+ attribute :name
545
+ attribute :account_ids
546
+ attribute :created_at, :time
547
+ attribute :updated_at, :time
35
548
  end
36
549
 
37
550
  # An account a post is targeted at, plus its per-account delivery state.
@@ -123,41 +636,195 @@ module Fopost
123
636
  attribute :external_url
124
637
  end
125
638
 
126
- class PageMeta < Model
127
- attribute :current_page
128
- attribute :per_page
129
- attribute :total
130
- attribute :last_page
131
- attribute :from
132
- attribute :to
639
+ # ── Analytics ────────────────────────────────────────────────────
640
+
641
+ # One age band of GET /analytics/decay.
642
+ class DecayBand < Model
643
+ attribute :bucket
644
+ attribute :label
645
+ # Posts with at least one reading in this band.
646
+ attribute :posts
647
+ attribute :avg_engagements
648
+ attribute :avg_impressions
649
+ # Mean share of the post's final engagement reached by this age, 0-1.
650
+ attribute :share_of_final
133
651
  end
134
652
 
135
- # One page of a list endpoint: its items plus the pagination meta.
136
- class Page
137
- include Enumerable
653
+ # How engagement accumulates as a post ages.
654
+ class ContentDecay < Model
655
+ attribute :days
656
+ attribute :posts_measured
657
+ # First band where the average post had passed half its final engagement.
658
+ attribute :half_life_bucket
659
+ attribute :bands, [DecayBand]
660
+ end
138
661
 
139
- attr_reader :items, :meta
662
+ class FrequencyWeek < Model
663
+ # Monday of the week, UTC, as YYYY-MM-DD.
664
+ attribute :week_start
665
+ attribute :posts
666
+ attribute :engagements
667
+ attribute :avg_engagements_per_post
668
+ end
140
669
 
141
- def initialize(items: [], meta: PageMeta.new)
142
- @items = items
143
- @meta = meta
144
- end
670
+ class FrequencyBand < Model
671
+ attribute :band
672
+ attribute :label
673
+ attribute :weeks
674
+ attribute :posts
675
+ attribute :avg_posts_per_week
676
+ attribute :avg_engagements_per_post
677
+ # Engagements over reach, impressions as the stand-in; nil with neither.
678
+ attribute :engagement_rate
679
+ end
145
680
 
146
- def each(&block)
147
- return items.each unless block
681
+ # Weekly cadence set against what each cadence earned per post.
682
+ class PostingFrequency < Model
683
+ attribute :days
684
+ attribute :weeks, [FrequencyWeek]
685
+ attribute :bands, [FrequencyBand]
686
+ # The cadence that earned the most per post; nil without posts.
687
+ attribute :best, FrequencyBand
688
+ end
148
689
 
149
- items.each(&block)
150
- self
151
- end
690
+ # What moved between one timeline point and the one before it.
691
+ class TimelineDelta < Model
692
+ attribute :impressions
693
+ attribute :reach
694
+ attribute :engagements
695
+ attribute :likes
696
+ attribute :comments
697
+ attribute :shares
698
+ end
152
699
 
153
- def [](index)
154
- items[index]
155
- end
700
+ class TimelinePoint < Model
701
+ attribute :at, :time
702
+ # Minutes since publication; nil when the network never said when.
703
+ attribute :age_minutes
704
+ attribute :impressions
705
+ attribute :reach
706
+ attribute :engagements
707
+ attribute :likes
708
+ attribute :comments
709
+ attribute :shares
710
+ attribute :video_views
711
+ attribute :delta, TimelineDelta
712
+ end
156
713
 
157
- def size
158
- items.size
159
- end
160
- alias length size
714
+ # One delivery's readings: the same post on two networks decays differently.
715
+ class TimelineDelivery < Model
716
+ attribute :account_id
717
+ attribute :platform
718
+ attribute :username
719
+ attribute :external_post_id
720
+ attribute :posted_at, :time
721
+ attribute :points, [TimelinePoint]
722
+ end
723
+
724
+ # Every reading held for one post, one timeline per delivery.
725
+ class PostTimeline < Model
726
+ # nil when the post was made natively on the network.
727
+ attribute :post_id
728
+ attribute :deliveries, [TimelineDelivery]
729
+ end
730
+
731
+ class MetricChange < Model
732
+ attribute :account_id
733
+ attribute :platform
734
+ attribute :external_post_id
735
+ # nil for a post made natively on the network.
736
+ attribute :post_id
737
+ attribute :posted_at, :time
738
+ attribute :fetched_at, :time
739
+ attribute :impressions
740
+ attribute :reach
741
+ attribute :engagements
742
+ attribute :likes
743
+ attribute :comments
744
+ attribute :shares
745
+ end
746
+
747
+ # Readings since a cursor, with the cursor to pass next time.
748
+ class MetricChangePage < Model
749
+ attribute :since, :time
750
+ # Feed back as `since` to continue; nil when nothing changed.
751
+ attribute :cursor, :time
752
+ attribute :has_more
753
+ attribute :changes, [MetricChange]
754
+ end
755
+
756
+ class CollectPostDelivery < Model
757
+ attribute :account_id
758
+ attribute :platform
759
+ attribute :external_post_id
760
+ attribute :collected
761
+ attribute :fetched_at, :time
762
+ # Why the refresh did not happen.
763
+ attribute :message
764
+ end
765
+
766
+ class CollectPostResult < Model
767
+ attribute :collected
768
+ attribute :deliveries, [CollectPostDelivery]
769
+ end
770
+
771
+ class NativePostMetrics < Model
772
+ attribute :impressions
773
+ attribute :reach
774
+ attribute :engagements
775
+ attribute :likes
776
+ attribute :comments
777
+ attribute :shares
778
+ attribute :video_views
779
+ end
780
+
781
+ # A post on the account that never went out through FoPost.
782
+ class NativePost < Model
783
+ attribute :external_post_id
784
+ attribute :text
785
+ attribute :permalink
786
+ attribute :thumbnail_url
787
+ attribute :media_type
788
+ attribute :posted_at, :time
789
+ attribute :fetched_at, :time
790
+ attribute :metrics, NativePostMetrics
791
+ end
792
+
793
+ class PageMeta < Model
794
+ attribute :current_page
795
+ attribute :per_page
796
+ attribute :total
797
+ attribute :last_page
798
+ attribute :from
799
+ attribute :to
800
+ end
801
+
802
+ # One page of a list endpoint: its items plus the pagination meta.
803
+ class Page
804
+ include Enumerable
805
+
806
+ attr_reader :items, :meta
807
+
808
+ def initialize(items: [], meta: PageMeta.new)
809
+ @items = items
810
+ @meta = meta
811
+ end
812
+
813
+ def each(&block)
814
+ return items.each unless block
815
+
816
+ items.each(&block)
817
+ self
818
+ end
819
+
820
+ def [](index)
821
+ items[index]
822
+ end
823
+
824
+ def size
825
+ items.size
826
+ end
827
+ alias length size
161
828
  alias count size
162
829
 
163
830
  def empty?
@@ -206,6 +873,49 @@ module Fopost
206
873
  attribute :credits, AiCredits
207
874
  end
208
875
 
876
+ # Advisory note from a validate call; never blocks publishing.
877
+ class ValidateSignal < Model
878
+ attribute :level
879
+ attribute :code
880
+ attribute :message
881
+ end
882
+
883
+ class ValidatePostPlatform < Model
884
+ attribute :platform
885
+ attribute :ready
886
+ attribute :issues
887
+ attribute :score
888
+ attribute :signals, [ValidateSignal]
889
+ end
890
+
891
+ class ValidatePostResult < Model
892
+ attribute :ready
893
+ attribute :platforms, [ValidatePostPlatform]
894
+ end
895
+
896
+ class ValidateLengthPlatform < Model
897
+ attribute :platform
898
+ attribute :length
899
+ attribute :limit
900
+ attribute :unit
901
+ attribute :ok
902
+ attribute :signals, [ValidateSignal]
903
+ end
904
+
905
+ class ValidateLengthResult < Model
906
+ attribute :ok
907
+ attribute :platforms, [ValidateLengthPlatform]
908
+ end
909
+
910
+ class ValidateMediaResult < Model
911
+ attribute :ok
912
+ attribute :issues
913
+ attribute :name
914
+ attribute :size
915
+ attribute :mime_type
916
+ attribute :type
917
+ end
918
+
209
919
  # `page`, `per_page`, `total` on the inbox list endpoints.
210
920
  class InboxPageMeta < Model
211
921
  attribute :page
@@ -245,7 +955,7 @@ module Fopost
245
955
  attribute :published, :hash
246
956
  end
247
957
 
248
- # A comment, mention or direct message on a connected account.
958
+ # A comment, mention, review or direct message on a connected account.
249
959
  class InboxItem < Model
250
960
  attribute :id
251
961
  attribute :workspace_id
@@ -258,6 +968,8 @@ module Fopost
258
968
  attribute :author_handle
259
969
  attribute :author_avatar_url
260
970
  attribute :text
971
+ # Stars on a review, 1-5. Nil on every other type.
972
+ attribute :rating
261
973
  attribute :attachments, [InboxAttachment]
262
974
  attribute :permalink
263
975
  attribute :post_external_id
@@ -268,8 +980,24 @@ module Fopost
268
980
  attribute :created_at, :time
269
981
  attribute :can_reply
270
982
  attribute :hidden
983
+ attribute :liked
984
+ # How the account voted where the network ranks by votes: 'up', 'down' or nil.
985
+ attribute :vote
986
+ attribute :pinned
987
+ attribute :reaction
988
+ attribute :edited_at, :time
271
989
  attribute :can_hide
272
990
  attribute :can_delete
991
+ attribute :can_like
992
+ attribute :can_vote
993
+ attribute :can_pin
994
+ attribute :can_edit
995
+ attribute :can_react
996
+ attribute :can_send_media
997
+ attribute :can_quick_reply
998
+ attribute :can_private_reply
999
+ # The platform's own state: published, held, spam or rejected.
1000
+ attribute :moderation_status
273
1001
  attribute :post, :hash
274
1002
  attribute :post_context, InboxPostContext
275
1003
  attribute :account, InboxAccountRef
@@ -285,6 +1013,8 @@ module Fopost
285
1013
  attribute :last_comment_at, :time
286
1014
  attribute :last_comment_text
287
1015
  attribute :last_comment_author
1016
+ # Stars, on a review thread. Nil on comments and mentions.
1017
+ attribute :rating
288
1018
  attribute :post, InboxPostContext
289
1019
  attribute :account, InboxAccountRef
290
1020
  end
@@ -314,6 +1044,46 @@ module Fopost
314
1044
  attribute :pending_reason
315
1045
  attribute :dm_supported
316
1046
  attribute :dm_pending_reason
1047
+ attribute :can_start_conversation
1048
+ # The grant predates a permission the inbox needs; reconnect the account once.
1049
+ attribute :reconnect_required
1050
+ end
1051
+
1052
+ # One thing the workspace has told FoPost about itself: an FAQ, a note, a page
1053
+ # on its own site, or a plain-text/CSV file from the media library.
1054
+ class KnowledgeSource < Model
1055
+ attribute :id
1056
+ # `faq`, `text`, `url` or `file`.
1057
+ attribute :kind
1058
+ attribute :title
1059
+ # Only a `ready` source is searched.
1060
+ attribute :status
1061
+ # Why the last sync failed, in plain words.
1062
+ attribute :status_message
1063
+ # Set for `url` sources.
1064
+ attribute :url
1065
+ # Set for `file` sources: the media library item read.
1066
+ attribute :media_id
1067
+ # nil means the source serves the whole workspace.
1068
+ attribute :brand_voice_id
1069
+ # Searchable passages the last sync produced.
1070
+ attribute :chunk_count
1071
+ # The typed text, for `faq` and `text` sources only.
1072
+ attribute :content
1073
+ attribute :last_synced_at, :time
1074
+ attribute :created_at, :time
1075
+ attribute :updated_at, :time
1076
+ end
1077
+
1078
+ # One retrieved passage, with the source it came from so a reply can cite it.
1079
+ class KnowledgeMatch < Model
1080
+ attribute :source_id
1081
+ attribute :source_title
1082
+ attribute :source_kind
1083
+ attribute :source_url
1084
+ attribute :text
1085
+ # Similarity to the question, 0-1.
1086
+ attribute :score
317
1087
  end
318
1088
 
319
1089
  class InboxPlatform < Model
@@ -337,6 +1107,12 @@ module Fopost
337
1107
  attribute :reply, :hash
338
1108
  end
339
1109
 
1110
+ # A DM opened by handle or as a private reply to a comment.
1111
+ class InboxStartedConversation < Model
1112
+ attribute :conversation_id
1113
+ attribute :item, InboxItem
1114
+ end
1115
+
340
1116
  class InboxRefreshResult < Model
341
1117
  attribute :accounts_polled
342
1118
  attribute :new_items
@@ -408,8 +1184,21 @@ module Fopost
408
1184
  end
409
1185
 
410
1186
  # A connection with the ad accounts and Pages its grant reaches.
1187
+ # An ad network from the API's registry. `configured` false cannot be connected yet.
1188
+ class AdProvider < Model
1189
+ attribute :id
1190
+ attribute :name
1191
+ attribute :logo
1192
+ attribute :configured
1193
+ attribute :connect_methods
1194
+ attribute :capabilities
1195
+ attribute :targeting_facets
1196
+ attribute :tracking_macros
1197
+ end
1198
+
411
1199
  class AdSource < Model
412
1200
  attribute :connection_id
1201
+ attribute :provider
413
1202
  attribute :name
414
1203
  attribute :workspace_id
415
1204
  attribute :ad_accounts
@@ -448,6 +1237,51 @@ module Fopost
448
1237
  attribute :detail
449
1238
  end
450
1239
 
1240
+ # A Business Center, or the network's equivalent grouping of ad accounts.
1241
+ class AdBusinessCenter < Model
1242
+ attribute :id
1243
+ attribute :name
1244
+ attribute :role
1245
+ end
1246
+
1247
+ # The account an ad runs as. Meta calls it a Page, TikTok an identity.
1248
+ class AdIdentity < Model
1249
+ attribute :id
1250
+ attribute :type
1251
+ attribute :name
1252
+ attribute :avatar_url
1253
+ end
1254
+
1255
+ # A post already live on the network, offered as the source of a Spark ad.
1256
+ class SparkPost < Model
1257
+ attribute :id
1258
+ attribute :identity_id
1259
+ attribute :caption
1260
+ attribute :thumbnail_url
1261
+ attribute :created_at
1262
+ attribute :views
1263
+ end
1264
+
1265
+ # A comment on an ad, read live from the network and never stored.
1266
+ class AdComment < Model
1267
+ attribute :id
1268
+ attribute :ad_id
1269
+ attribute :text
1270
+ attribute :author_name
1271
+ attribute :author_avatar_url
1272
+ attribute :created_at
1273
+ attribute :likes
1274
+ attribute :reply_count
1275
+ attribute :hidden
1276
+ attribute :parent_id
1277
+ end
1278
+
1279
+ # One page of an ad's comments; pass `next_cursor` back as `after`.
1280
+ class AdCommentsPage < Model
1281
+ attribute :comments, [AdComment]
1282
+ attribute :next_cursor
1283
+ end
1284
+
451
1285
  class LeadForm < Model
452
1286
  attribute :id
453
1287
  attribute :name
@@ -482,4 +1316,997 @@ module Fopost
482
1316
  attribute :leads, [Lead]
483
1317
  attribute :next_cursor
484
1318
  end
1319
+
1320
+ # A Meta ad inside an ad set. Read live from Meta, never stored.
1321
+ class NetworkAd < Model
1322
+ attribute :id
1323
+ attribute :name
1324
+ attribute :campaign_id
1325
+ attribute :ad_set_id
1326
+ attribute :creative_id
1327
+ attribute :status
1328
+ attribute :effective_status
1329
+ attribute :created_at, :time
1330
+ end
1331
+
1332
+ class AdSet < Model
1333
+ attribute :id
1334
+ attribute :name
1335
+ attribute :campaign_id
1336
+ attribute :status
1337
+ attribute :effective_status
1338
+ attribute :budget_minor
1339
+ attribute :budget_type
1340
+ attribute :end_at, :time
1341
+ attribute :optimization_goal
1342
+ attribute :created_at, :time
1343
+ attribute :ads, [NetworkAd]
1344
+ end
1345
+
1346
+ class AdCampaign < Model
1347
+ attribute :id
1348
+ attribute :name
1349
+ attribute :status
1350
+ attribute :effective_status
1351
+ attribute :objective
1352
+ attribute :budget_minor
1353
+ attribute :budget_type
1354
+ attribute :created_at, :time
1355
+ attribute :ad_sets, [AdSet]
1356
+ end
1357
+
1358
+ # Campaigns with their ad sets and ads, read live from Meta.
1359
+ class AdAccountTree < Model
1360
+ attribute :ad_account_id
1361
+ attribute :currency
1362
+ attribute :workspace_id
1363
+ attribute :campaigns, [AdCampaign]
1364
+ end
1365
+
1366
+ class BulkAdStatusResult < Model
1367
+ attribute :id
1368
+ attribute :level
1369
+ attribute :ok
1370
+ attribute :error
1371
+ end
1372
+
1373
+ class AdCreative < Model
1374
+ attribute :id
1375
+ attribute :name
1376
+ attribute :format
1377
+ attribute :status
1378
+ attribute :title
1379
+ attribute :body
1380
+ attribute :link
1381
+ attribute :thumbnail_url
1382
+ attribute :call_to_action
1383
+ attribute :url_tags
1384
+ end
1385
+
1386
+ # ─── Product catalogs ──────────────────────────────────────────
1387
+
1388
+ # A product catalog on the connection's business portfolio, read live.
1389
+ class ProductCatalog < Model
1390
+ attribute :id
1391
+ attribute :name
1392
+ attribute :vertical
1393
+ attribute :product_count
1394
+ end
1395
+
1396
+ class ProductCatalogsResult < Model
1397
+ attribute :catalogs, [ProductCatalog]
1398
+ attribute :workspace_id
1399
+ end
1400
+
1401
+ # One product in a catalog. `price_minor` is minor units of `currency`.
1402
+ class CatalogProduct < Model
1403
+ attribute :id
1404
+ # Your own key for the product.
1405
+ attribute :retailer_id
1406
+ attribute :name
1407
+ attribute :description
1408
+ attribute :availability
1409
+ attribute :condition
1410
+ attribute :price_minor
1411
+ attribute :currency
1412
+ attribute :image_url
1413
+ attribute :url
1414
+ end
1415
+
1416
+ class CatalogProductsPage < Model
1417
+ attribute :products, [CatalogProduct]
1418
+ attribute :next_cursor
1419
+ end
1420
+
1421
+ class CatalogBatchResult < Model
1422
+ attribute :handles
1423
+ # Products sent in this batch.
1424
+ attribute :accepted
1425
+ end
1426
+
1427
+ # Keeps a catalog in step with a product file you host.
1428
+ class ProductFeed < Model
1429
+ attribute :id
1430
+ attribute :name
1431
+ attribute :url
1432
+ attribute :schedule
1433
+ attribute :created_at, :time
1434
+ end
1435
+
1436
+ class ProductFeedUpload < Model
1437
+ attribute :id
1438
+ attribute :started_at, :time
1439
+ attribute :ended_at, :time
1440
+ attribute :status
1441
+ attribute :error_count
1442
+ attribute :warning_count
1443
+ end
1444
+
1445
+ # The slice of a catalog one catalog ad runs from.
1446
+ class ProductSet < Model
1447
+ attribute :id
1448
+ attribute :name
1449
+ attribute :product_count
1450
+ # The network's own product-set filter.
1451
+ attribute :filter
1452
+ end
1453
+
1454
+ # ─── Reach and frequency ───────────────────────────────────────
1455
+
1456
+ # A priced flight. Nothing is bought until it is reserved.
1457
+ class ReachFrequencyPrediction < Model
1458
+ attribute :id
1459
+ attribute :name
1460
+ attribute :status
1461
+ attribute :reach
1462
+ attribute :impressions
1463
+ attribute :frequency_cap
1464
+ # Account currency, minor units.
1465
+ attribute :budget_minor
1466
+ attribute :start_at, :time
1467
+ attribute :end_at, :time
1468
+ # True once the prediction holds inventory.
1469
+ attribute :reserved
1470
+ end
1471
+
1472
+ class ReachFrequencyResult < Model
1473
+ attribute :predictions, [ReachFrequencyPrediction]
1474
+ attribute :workspace_id
1475
+ end
1476
+
1477
+ # ─── Ad Library ────────────────────────────────────────────────
1478
+
1479
+ # One public archive entry. Read live on every search and stored nowhere.
1480
+ class AdLibraryEntry < Model
1481
+ attribute :id
1482
+ attribute :page_id
1483
+ attribute :page_name
1484
+ attribute :bodies
1485
+ attribute :titles
1486
+ attribute :link_urls
1487
+ attribute :snapshot_url
1488
+ attribute :publisher_platforms
1489
+ attribute :started_at, :time
1490
+ attribute :ended_at, :time
1491
+ # Only on the archive's disclosure entries.
1492
+ attribute :currency
1493
+ attribute :spend_lower
1494
+ attribute :spend_upper
1495
+ attribute :impressions_lower
1496
+ attribute :impressions_upper
1497
+ end
1498
+
1499
+ class AdLibraryPage < Model
1500
+ attribute :entries, [AdLibraryEntry]
1501
+ attribute :next_cursor
1502
+ end
1503
+
1504
+ # ─── Partnership ads ───────────────────────────────────────────
1505
+
1506
+ # A creator who allowlisted this advertiser for partnership ads.
1507
+ class PartnershipCreator < Model
1508
+ attribute :id
1509
+ attribute :username
1510
+ attribute :name
1511
+ attribute :status
1512
+ attribute :permissions
1513
+ end
1514
+
1515
+ # ─── Ad account settings ───────────────────────────────────────
1516
+
1517
+ class AdActivity < Model
1518
+ attribute :id
1519
+ attribute :event_type
1520
+ attribute :actor_name
1521
+ attribute :object_name
1522
+ attribute :object_type
1523
+ attribute :extra_data
1524
+ attribute :created_at, :time
1525
+ end
1526
+
1527
+ class AdActivityResult < Model
1528
+ attribute :activity, [AdActivity]
1529
+ attribute :workspace_id
1530
+ end
1531
+
1532
+ # Groups campaigns, ad sets and ads for reporting.
1533
+ class AdLabel < Model
1534
+ attribute :id
1535
+ attribute :name
1536
+ attribute :created_at, :time
1537
+ end
1538
+
1539
+ # An A/B study splitting traffic across its cells.
1540
+ class AdStudy < Model
1541
+ attribute :id
1542
+ attribute :name
1543
+ attribute :description
1544
+ attribute :type
1545
+ attribute :status
1546
+ attribute :start_at, :time
1547
+ attribute :end_at, :time
1548
+ end
1549
+
1550
+ # How many iOS 14 campaigns an ad account may run at once, per app.
1551
+ class IosCampaignLimits < Model
1552
+ attribute :limit
1553
+ attribute :used
1554
+ attribute :app_id
1555
+ end
1556
+
1557
+ # A window the network should expect heavier spend over.
1558
+ class HighDemandPeriod < Model
1559
+ attribute :id
1560
+ attribute :start_at, :time
1561
+ attribute :end_at, :time
1562
+ attribute :budget_value
1563
+ attribute :budget_value_type
1564
+ end
1565
+
1566
+ # Weights conversions so some audiences count for more than others.
1567
+ class ValueRuleSet < Model
1568
+ attribute :id
1569
+ attribute :name
1570
+ attribute :status
1571
+ attribute :rules
1572
+ end
1573
+
1574
+ class ReachEstimate < Model
1575
+ attribute :lower
1576
+ attribute :upper
1577
+ attribute :ready
1578
+ end
1579
+
1580
+ # What the auction costs, in minor units of the ad account currency.
1581
+ class BidPricing < Model
1582
+ attribute :currency
1583
+ attribute :suggested_bid_minor
1584
+ attribute :min_bid_minor
1585
+ attribute :max_bid_minor
1586
+ attribute :daily_budget_floor_minor
1587
+ end
1588
+
1589
+ # What an audience would deliver at a budget, over the network's own window.
1590
+ class SupplyForecast < Model
1591
+ attribute :currency
1592
+ attribute :impressions
1593
+ attribute :clicks
1594
+ attribute :spend_minor
1595
+ attribute :window_days
1596
+ attribute :ready
1597
+ end
1598
+
1599
+ # How the network attributes a sale or a sign-up back to an ad set.
1600
+ class ConversionRule < Model
1601
+ attribute :id
1602
+ attribute :name
1603
+ attribute :type
1604
+ attribute :attribution
1605
+ attribute :post_click_window_days
1606
+ attribute :view_through_window_days
1607
+ attribute :value_minor
1608
+ attribute :currency
1609
+ attribute :enabled
1610
+ attribute :created_at
1611
+ attribute :campaign_ids
1612
+ end
1613
+
1614
+ class ConversionMetrics < Model
1615
+ attribute :conversions
1616
+ attribute :post_click_conversions
1617
+ attribute :view_through_conversions
1618
+ attribute :value_minor
1619
+ attribute :cost_per_conversion_minor
1620
+ end
1621
+
1622
+ # `spend_minor` is in the ad account currency, minor units; `ctr` is a percentage.
1623
+ class InsightsMetrics < Model
1624
+ attribute :impressions
1625
+ attribute :reach
1626
+ attribute :clicks
1627
+ attribute :spend_minor
1628
+ attribute :ctr
1629
+ attribute :leads
1630
+ end
1631
+
1632
+ class InsightsBreakdownRow < Model
1633
+ attribute :key
1634
+ attribute :metrics, InsightsMetrics
1635
+ end
1636
+
1637
+ class InsightsTimelineRow < Model
1638
+ attribute :date
1639
+ attribute :metrics, InsightsMetrics
1640
+ end
1641
+
1642
+ class AdInsightsReport < Model
1643
+ attribute :currency
1644
+ attribute :since
1645
+ attribute :until
1646
+ attribute :breakdown_by
1647
+ attribute :totals, InsightsMetrics
1648
+ attribute :breakdown, [InsightsBreakdownRow]
1649
+ attribute :timeline, [InsightsTimelineRow]
1650
+
1651
+ # The Meta id the report covers; `object_id` is taken by Ruby itself.
1652
+ def meta_object_id
1653
+ self['objectId']
1654
+ end
1655
+ end
1656
+
1657
+ class LeadFormDetail < Model
1658
+ attribute :id
1659
+ attribute :name
1660
+ attribute :status
1661
+ attribute :leads_count
1662
+ attribute :created_at, :time
1663
+ attribute :questions
1664
+ attribute :page_id
1665
+ attribute :privacy_policy_url
1666
+ attribute :locale
1667
+ end
1668
+
1669
+ # A lead stored from a subscribed Page.
1670
+ class FeedLead < Model
1671
+ attribute :id
1672
+ attribute :lead_id
1673
+ attribute :connection_id
1674
+ attribute :page_id
1675
+ attribute :form_id
1676
+ attribute :ad_id
1677
+ attribute :ad_name
1678
+ attribute :campaign_name
1679
+ attribute :platform
1680
+ attribute :is_organic
1681
+ attribute :fields
1682
+ attribute :submitted_at, :time
1683
+ attribute :workspace_id
1684
+ end
1685
+
1686
+ # One page of the leads feed; pass `next_cursor` back as `cursor:` for the next.
1687
+ class LeadsFeedPage < Model
1688
+ attribute :leads, [FeedLead]
1689
+ attribute :next_cursor
1690
+ end
1691
+
1692
+ # Who did something: `user`, `api_key`, `agent` or `system`.
1693
+ class ActivityActor < Model
1694
+ attribute :type
1695
+ attribute :name
1696
+ end
1697
+
1698
+ # One thing that happened in a workspace. A `security` kind is an audit row.
1699
+ class ActivityEvent < Model
1700
+ attribute :id
1701
+ attribute :workspace_id
1702
+ attribute :kind
1703
+ attribute :ref_type
1704
+ attribute :ref_id
1705
+ attribute :summary
1706
+ attribute :actor, ActivityActor
1707
+ attribute :time, :time
1708
+ end
1709
+
1710
+ # One page of activity; pass `next_cursor` back as `cursor:` for the next.
1711
+ class ActivityPage < Model
1712
+ attribute :events, [ActivityEvent]
1713
+ attribute :next_cursor
1714
+ end
1715
+
1716
+ class LeadPage < Model
1717
+ attribute :connection_id
1718
+ attribute :page_id
1719
+ attribute :page_name
1720
+ attribute :created_at, :time
1721
+ attribute :workspace_id
1722
+ end
1723
+ # ─── Contacts ────────────────────────────────────────────────────
1724
+
1725
+ # One handle on one network. The handle is lower-cased with no leading @.
1726
+ class ContactChannel < Model
1727
+ attribute :platform
1728
+ attribute :handle
1729
+ # The platform's own id for this person, when the network gave us one.
1730
+ attribute :external_id
1731
+ end
1732
+
1733
+ class ContactLabel < Model
1734
+ attribute :id
1735
+ attribute :name
1736
+ attribute :color
1737
+ end
1738
+
1739
+ # One person, however many handles they write from.
1740
+ class Contact < Model
1741
+ attribute :id
1742
+ attribute :display_name
1743
+ attribute :channels, [ContactChannel]
1744
+ # inbox, radar or import — what first created the row.
1745
+ attribute :source
1746
+ attribute :note
1747
+ attribute :first_seen_at, :time
1748
+ attribute :last_seen_at, :time
1749
+ # Custom field values, keyed by field key.
1750
+ attribute :fields, :hash
1751
+ attribute :labels, [ContactLabel]
1752
+ # Only on a listing that spans workspaces.
1753
+ attribute :workspace_id
1754
+ end
1755
+
1756
+ # One thread a contact appears in.
1757
+ class ContactConversation < Model
1758
+ # How the inbox groups it: DM thread id, else root post id, else handle.
1759
+ attribute :key
1760
+ attribute :account_id
1761
+ attribute :account_username
1762
+ attribute :platform
1763
+ attribute :messages
1764
+ attribute :received
1765
+ attribute :sent
1766
+ attribute :last_message_at, :time
1767
+ attribute :last_item_id
1768
+ end
1769
+
1770
+ class ContactImportSkip < Model
1771
+ attribute :row
1772
+ attribute :reason
1773
+ end
1774
+
1775
+ # What a CSV import did.
1776
+ class ContactImportResult < Model
1777
+ attribute :created
1778
+ # Rows that folded into a contact already on file.
1779
+ attribute :merged
1780
+ attribute :skipped, [ContactImportSkip]
1781
+ # Columns that named neither a reserved field nor a custom field.
1782
+ attribute :unknown_columns
1783
+ end
1784
+
1785
+ # A column the workspace invented to keep about its contacts.
1786
+ class ContactField < Model
1787
+ attribute :id
1788
+ # Lower-case key, also the CSV column header. Fixed once created.
1789
+ attribute :key
1790
+ attribute :name
1791
+ # text, number, date, select or boolean.
1792
+ attribute :type
1793
+ # Allowed values when the type is select.
1794
+ attribute :options
1795
+ attribute :position
1796
+ end
1797
+
1798
+ class ConversationAnalyticsRow < Model
1799
+ attribute :key
1800
+ attribute :account_id
1801
+ attribute :platform
1802
+ attribute :received
1803
+ attribute :sent
1804
+ attribute :answered
1805
+ attribute :open
1806
+ # Median minutes to the first reply in this thread.
1807
+ attribute :median_response_minutes
1808
+ attribute :first_message_at, :time
1809
+ attribute :last_message_at, :time
1810
+ end
1811
+
1812
+ # Inbox analytics broken out per thread.
1813
+ class ConversationAnalytics < Model
1814
+ attribute :conversations, [ConversationAnalyticsRow]
1815
+ attribute :total
1816
+ attribute :page
1817
+ attribute :per_page
1818
+ end
1819
+
1820
+ # The pagination block a contacts listing returns.
1821
+ class ContactPageMeta < Model
1822
+ attribute :page
1823
+ attribute :per_page
1824
+ attribute :total
1825
+ end
1826
+
1827
+ # ─── Broadcasts and sequences ────────────────────────────────────
1828
+
1829
+ # What became of a broadcast's recipients, by status.
1830
+ class BroadcastCounts < Model
1831
+ attribute :total
1832
+ attribute :sent
1833
+ # Usually the messaging window doing its job.
1834
+ attribute :skipped
1835
+ attribute :failed
1836
+ attribute :pending
1837
+ end
1838
+
1839
+ # One message, sent into conversations the workspace already has.
1840
+ class Broadcast < Model
1841
+ attribute :id
1842
+ # Internal only; never sent to anyone.
1843
+ attribute :name
1844
+ attribute :text
1845
+ attribute :account_id
1846
+ attribute :audience, :hash
1847
+ # draft, scheduled, sending, sent or cancelled.
1848
+ attribute :status
1849
+ attribute :scheduled_at, :time
1850
+ attribute :sent_at, :time
1851
+ attribute :created_at, :time
1852
+ attribute :counts, BroadcastCounts
1853
+ # Only on a listing that spans workspaces.
1854
+ attribute :workspace_id
1855
+ end
1856
+
1857
+ # One contact on one broadcast, and what became of their message.
1858
+ class BroadcastRecipient < Model
1859
+ attribute :contact_id
1860
+ attribute :display_name
1861
+ # pending, sent, skipped or failed.
1862
+ attribute :status
1863
+ # Why nothing was sent: window_closed, no_conversation or
1864
+ # unsupported_platform. window_closed means the network's messaging
1865
+ # window had shut, so nothing was attempted.
1866
+ attribute :skip_reason
1867
+ attribute :sent_at, :time
1868
+ attribute :error
1869
+ end
1870
+
1871
+ # One message and how long after the previous step it goes out.
1872
+ class SequenceStep < Model
1873
+ attribute :delay_hours
1874
+ attribute :text
1875
+ attribute :media_id
1876
+ end
1877
+
1878
+ # Where a sequence's enrollments stand, by status.
1879
+ class SequenceEnrollmentCounts < Model
1880
+ attribute :total
1881
+ attribute :active
1882
+ attribute :completed
1883
+ attribute :stopped
1884
+ attribute :failed
1885
+ end
1886
+
1887
+ # A series of messages, each a delay after the one before.
1888
+ class Sequence < Model
1889
+ attribute :id
1890
+ attribute :name
1891
+ attribute :account_id
1892
+ attribute :steps, [SequenceStep]
1893
+ # active or paused. A paused sequence fires nothing.
1894
+ attribute :status
1895
+ attribute :created_at, :time
1896
+ attribute :enrollments, SequenceEnrollmentCounts
1897
+ # Only on a listing that spans workspaces.
1898
+ attribute :workspace_id
1899
+ end
1900
+
1901
+ # One contact walking one sequence.
1902
+ class Enrollment < Model
1903
+ attribute :id
1904
+ attribute :contact_id
1905
+ attribute :display_name
1906
+ # Steps already sent, so also the index of the next one.
1907
+ attribute :step
1908
+ attribute :next_at, :time
1909
+ # active, completed, stopped or failed.
1910
+ attribute :status
1911
+ attribute :last_sent_at, :time
1912
+ # On a skipped step, the reason it was skipped.
1913
+ attribute :error
1914
+ end
1915
+
1916
+ # ─── Google Ads ───────────────────────────────────────────────────
1917
+
1918
+ # A keyword on an ad group. `id` is `<customer_id>~keyword~<ad_group_id>~<criterion_id>`.
1919
+ class GoogleKeyword < Model
1920
+ attribute :id
1921
+ attribute :ad_group_id
1922
+ attribute :text
1923
+ attribute :match_type
1924
+ attribute :status
1925
+ # Account currency, minor units.
1926
+ attribute :cpc_bid_minor
1927
+ attribute :negative
1928
+ end
1929
+
1930
+ class GoogleKeywordIdea < Model
1931
+ attribute :text
1932
+ attribute :avg_monthly_searches
1933
+ attribute :competition
1934
+ attribute :low_top_of_page_bid_minor
1935
+ attribute :high_top_of_page_bid_minor
1936
+ end
1937
+
1938
+ class GoogleSearchTerm < Model
1939
+ attribute :term
1940
+ attribute :ad_group_id
1941
+ attribute :status
1942
+ attribute :metrics
1943
+ end
1944
+
1945
+ class GoogleBidStrategy < Model
1946
+ attribute :id
1947
+ attribute :name
1948
+ attribute :type
1949
+ attribute :status
1950
+ attribute :campaign_count
1951
+ end
1952
+
1953
+ class GoogleAdScheduleSlot < Model
1954
+ attribute :id
1955
+ attribute :day_of_week
1956
+ attribute :start_hour
1957
+ attribute :end_hour
1958
+ attribute :bid_modifier
1959
+ end
1960
+
1961
+ # A negative keyword list.
1962
+ class GoogleSharedSet < Model
1963
+ attribute :id
1964
+ attribute :name
1965
+ attribute :type
1966
+ attribute :member_count
1967
+ end
1968
+
1969
+ # A sitelink, callout or structured snippet.
1970
+ class GoogleAsset < Model
1971
+ attribute :id
1972
+ attribute :name
1973
+ attribute :type
1974
+ attribute :text
1975
+ attribute :final_url
1976
+ end
1977
+
1978
+ # Where an asset is attached; an asset with no links serves nowhere.
1979
+ class GoogleAssetLink < Model
1980
+ attribute :id
1981
+ attribute :asset_id
1982
+ attribute :level
1983
+ attribute :owner_id
1984
+ attribute :field_type
1985
+ attribute :status
1986
+ end
1987
+
1988
+ # A Performance Max asset group.
1989
+ class GoogleAssetGroup < Model
1990
+ attribute :id
1991
+ attribute :campaign_id
1992
+ attribute :name
1993
+ attribute :status
1994
+ attribute :final_urls
1995
+ end
1996
+
1997
+ # A lead from Local Services Ads, read live and never stored.
1998
+ class GoogleLocalServicesLead < Model
1999
+ attribute :id
2000
+ attribute :category
2001
+ attribute :service
2002
+ attribute :contact_name
2003
+ attribute :phone
2004
+ attribute :email
2005
+ attribute :status
2006
+ attribute :type
2007
+ attribute :created_at
2008
+ end
2009
+
2010
+ class GoogleConversionAction < Model
2011
+ attribute :id
2012
+ attribute :name
2013
+ attribute :category
2014
+ attribute :status
2015
+ attribute :type
2016
+ attribute :counting_type
2017
+ attribute :value_minor
2018
+ end
2019
+
2020
+ # What Google projects applying a recommendation would change.
2021
+ class GoogleRecommendationImpact < Model
2022
+ attribute :base_clicks
2023
+ attribute :potential_clicks
2024
+ attribute :base_cost_minor
2025
+ attribute :potential_cost_minor
2026
+ attribute :base_conversions
2027
+ attribute :potential_conversions
2028
+ end
2029
+
2030
+ # One of Google's own recommendations. The id is the Google resource name
2031
+ # rather than the `~` form other objects use, because a recommendation is not
2032
+ # an object you address again: it is what apply and dismiss take.
2033
+ class GoogleRecommendation < Model
2034
+ attribute :id
2035
+ attribute :type
2036
+ attribute :campaign_id
2037
+ attribute :ad_group_id
2038
+ attribute :dismissed
2039
+ attribute :impact, GoogleRecommendationImpact
2040
+ end
2041
+
2042
+ class GoogleOptimizationScoreCampaign < Model
2043
+ attribute :id
2044
+ attribute :name
2045
+ attribute :score
2046
+ end
2047
+
2048
+ # Google's estimate of how well the account is set up, from 0 to 1.
2049
+ class GoogleOptimizationScore < Model
2050
+ attribute :score
2051
+ attribute :weight
2052
+ attribute :campaigns, [GoogleOptimizationScoreCampaign]
2053
+ end
2054
+
2055
+ # ─── Blog ─────────────────────────────────────────────────────────
2056
+
2057
+ # The last keyword research run.
2058
+ class BlogPlanRun < Model
2059
+ # queued, running, done or failed.
2060
+ attribute :status
2061
+ attribute :error
2062
+ # New keywords the run found.
2063
+ attribute :added
2064
+ attribute :finished_at, :time
2065
+ end
2066
+
2067
+ # Where articles publish, what the blog is for and how often it is planned.
2068
+ # `website_secret` is never on this model; it is shown once, on the update
2069
+ # that first sets `website_url`, or on a rotation.
2070
+ class BlogSettings < Model
2071
+ attribute :site_url
2072
+ attribute :topic
2073
+ attribute :audience
2074
+ # traffic, leads, sales, signups or authority.
2075
+ attribute :goal
2076
+ attribute :focus_topics
2077
+ attribute :avoid_topics
2078
+ attribute :language
2079
+ attribute :location_code
2080
+ # Articles planned per week; 0 turns planning off.
2081
+ attribute :cadence_per_week
2082
+ # Days before its planned date that a picked keyword starts being written.
2083
+ attribute :review_hold_days
2084
+ # draft, standard or best.
2085
+ attribute :image_tier
2086
+ attribute :in_body_images
2087
+ attribute :min_words
2088
+ attribute :max_words
2089
+ attribute :brand_voice_id
2090
+ # product_blog, account or website.
2091
+ attribute :target_kind
2092
+ attribute :target_account_id
2093
+ attribute :target_platform
2094
+ attribute :website_url
2095
+ attribute :has_website_secret
2096
+ # Nil before the first run.
2097
+ attribute :plan_run, BlogPlanRun
2098
+ attribute :keyword_data_available
2099
+ attribute :updated_at, :time
2100
+ end
2101
+
2102
+ # What a settings update answers: the settings, plus the website secret on
2103
+ # the one update that first set `website_url`.
2104
+ class BlogSettingsUpdate < Model
2105
+ attribute :settings, BlogSettings
2106
+ attribute :website_secret
2107
+ end
2108
+
2109
+ # The outcome of a test delivery to `website_url`.
2110
+ class BlogWebsiteTest < Model
2111
+ # What the website answered.
2112
+ attribute :http_status
2113
+ end
2114
+
2115
+ class BlogKeyword < Model
2116
+ attribute :id
2117
+ attribute :keyword
2118
+ attribute :search_volume
2119
+ # 0 to 100.
2120
+ attribute :difficulty
2121
+ attribute :cpc
2122
+ attribute :intent
2123
+ # provider, user or agent.
2124
+ attribute :source
2125
+ # suggested, planned, written or dismissed.
2126
+ attribute :status
2127
+ # A date, YYYY-MM-DD.
2128
+ attribute :planned_for
2129
+ # Why the keyword serves the blog goal.
2130
+ attribute :fit_reason
2131
+ attribute :created_at, :time
2132
+ end
2133
+
2134
+ class BlogArticleImage < Model
2135
+ attribute :media_id
2136
+ attribute :url
2137
+ attribute :alt
2138
+ # Index of the outline heading the image sits under; absent on the featured image.
2139
+ attribute :position
2140
+ end
2141
+
2142
+ # One article as a listing shows it, without the body.
2143
+ class BlogArticle < Model
2144
+ attribute :id
2145
+ attribute :title
2146
+ attribute :slug
2147
+ attribute :keyword
2148
+ attribute :excerpt
2149
+ attribute :meta_title
2150
+ attribute :meta_description
2151
+ attribute :featured_image, BlogArticleImage
2152
+ attribute :tags
2153
+ attribute :word_count
2154
+ # queued, writing, draft, in_review, scheduled, publishing, published, failed or rejected.
2155
+ attribute :status
2156
+ # plan, user or agent.
2157
+ attribute :origin
2158
+ attribute :review_until, :time
2159
+ attribute :publish_at, :time
2160
+ attribute :published_at, :time
2161
+ attribute :published_url
2162
+ attribute :error
2163
+ attribute :created_at, :time
2164
+ attribute :updated_at, :time
2165
+ end
2166
+
2167
+ # An article with its body, outline and images.
2168
+ class BlogArticleFull < BlogArticle
2169
+ attribute :instructions
2170
+ attribute :outline
2171
+ # The research the writer worked from.
2172
+ attribute :brief, :hash
2173
+ attribute :body_markdown
2174
+ attribute :body_html
2175
+ attribute :images, [BlogArticleImage]
2176
+ end
2177
+
2178
+ # The `data` of an `article.published` webhook. Image URLs stay fetchable
2179
+ # for six hours; a receiver stores its own copy.
2180
+ class BlogArticlePublished < Model
2181
+ attribute :id
2182
+ attribute :title
2183
+ attribute :slug
2184
+ attribute :excerpt
2185
+ attribute :meta_title
2186
+ attribute :meta_description
2187
+ attribute :body_markdown
2188
+ attribute :body_html
2189
+ attribute :featured_image, BlogArticleImage
2190
+ attribute :images, [BlogArticleImage]
2191
+ attribute :tags
2192
+ attribute :keyword
2193
+ attribute :word_count
2194
+ attribute :published_at, :time
2195
+ attribute :published_url
2196
+ end
2197
+
2198
+ # The envelope every FoPost webhook delivers, after its signature checked out.
2199
+ class WebhookEvent < Model
2200
+ attribute :event
2201
+ attribute :data, :hash
2202
+ attribute :timestamp, :time
2203
+
2204
+ # The typed payload of an `article.published` (or `article.test`) delivery.
2205
+ def article
2206
+ BlogArticlePublished.new(data)
2207
+ end
2208
+ end
2209
+
2210
+ # ─── WhatsApp Business ─────────────────────────────────────────
2211
+ #
2212
+ # The platform owns these resources, so nothing here is a cached copy: a
2213
+ # template's status is whatever the platform assigned it.
2214
+
2215
+ # A message template on a WhatsApp Business Account.
2216
+ class WhatsappTemplate < Model
2217
+ attribute :id
2218
+ attribute :name
2219
+ attribute :language
2220
+ attribute :category
2221
+ # The review status the platform assigned: APPROVED, PENDING, REJECTED, …
2222
+ attribute :status
2223
+ attribute :rejected_reason
2224
+ attribute :components
2225
+ attribute :quality_score
2226
+ end
2227
+
2228
+ # The business profile on a WhatsApp number, plus its quality and limit tier.
2229
+ class WhatsappProfile < Model
2230
+ attribute :about
2231
+ attribute :address
2232
+ attribute :description
2233
+ attribute :email
2234
+ attribute :vertical
2235
+ attribute :websites
2236
+ attribute :profile_picture_url
2237
+ attribute :display_name
2238
+ # The platform's review state for the display name.
2239
+ attribute :display_name_status
2240
+ attribute :username
2241
+ attribute :quality_rating
2242
+ attribute :messaging_limit_tier
2243
+ end
2244
+
2245
+ # A group on a WhatsApp number. Participation is invite-only.
2246
+ class WhatsappGroup < Model
2247
+ attribute :id
2248
+ attribute :subject
2249
+ attribute :description
2250
+ attribute :participant_count
2251
+ attribute :invite_link
2252
+ attribute :created_at, :time
2253
+ end
2254
+
2255
+ # What the platform took and what it refused.
2256
+ class WhatsappBlockResult < Model
2257
+ attribute :blocked
2258
+ attribute :unblocked
2259
+ attribute :failed
2260
+ end
2261
+
2262
+ # Whether the cart and catalog show on the number, and which catalog is linked.
2263
+ class WhatsappCommerceSettings < Model
2264
+ attribute :cart_enabled
2265
+ attribute :catalog_visible
2266
+ attribute :catalog_id
2267
+ end
2268
+
2269
+ # An in-chat form. The platform validates it and owns its status.
2270
+ class WhatsappFlow < Model
2271
+ attribute :id
2272
+ attribute :name
2273
+ attribute :status
2274
+ attribute :categories
2275
+ attribute :validation_errors
2276
+ attribute :endpoint_uri
2277
+ attribute :json_version
2278
+ attribute :preview_url
2279
+ attribute :preview_expires_at, :time
2280
+ end
2281
+
2282
+ # The platform answers a flow upload with its validation errors, not a refusal.
2283
+ class WhatsappFlowJsonResult < Model
2284
+ attribute :success
2285
+ attribute :validation_errors
2286
+ end
2287
+
2288
+ # What one person submitted through a flow.
2289
+ class WhatsappFlowResponse < Model
2290
+ attribute :message_id
2291
+ attribute :wa_id
2292
+ attribute :flow_token
2293
+ attribute :answers
2294
+ attribute :responded_at, :time
2295
+ end
2296
+
2297
+ # Whether a key is registered. The key itself never comes back.
2298
+ class WhatsappEncryptionKeyStatus < Model
2299
+ attribute :has_key
2300
+ attribute :signature_status
2301
+ end
2302
+
2303
+ # A sandbox invitation. The tester's number is never stored in full.
2304
+ class WhatsappSandboxSession < Model
2305
+ attribute :id
2306
+ attribute :status
2307
+ attribute :phone_number_last4
2308
+ attribute :invited_at, :time
2309
+ attribute :activated_at, :time
2310
+ attribute :expires_at, :time
2311
+ end
485
2312
  end