late-sdk 0.0.913 → 0.0.914

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.
@@ -0,0 +1,174 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Zernio
17
+ class PinInboxComment200Response < ApiModelBase
18
+ attr_accessor :status
19
+
20
+ attr_accessor :comment_id
21
+
22
+ attr_accessor :pinned
23
+
24
+ attr_accessor :platform
25
+
26
+ # Attribute mapping from ruby-style variable name to JSON key.
27
+ def self.attribute_map
28
+ {
29
+ :'status' => :'status',
30
+ :'comment_id' => :'commentId',
31
+ :'pinned' => :'pinned',
32
+ :'platform' => :'platform'
33
+ }
34
+ end
35
+
36
+ # Returns attribute mapping this model knows about
37
+ def self.acceptable_attribute_map
38
+ attribute_map
39
+ end
40
+
41
+ # Returns all the JSON keys this model knows about
42
+ def self.acceptable_attributes
43
+ acceptable_attribute_map.values
44
+ end
45
+
46
+ # Attribute type mapping.
47
+ def self.openapi_types
48
+ {
49
+ :'status' => :'String',
50
+ :'comment_id' => :'String',
51
+ :'pinned' => :'Boolean',
52
+ :'platform' => :'String'
53
+ }
54
+ end
55
+
56
+ # List of attributes with nullable: true
57
+ def self.openapi_nullable
58
+ Set.new([
59
+ ])
60
+ end
61
+
62
+ # Initializes the object
63
+ # @param [Hash] attributes Model attributes in the form of hash
64
+ def initialize(attributes = {})
65
+ if (!attributes.is_a?(Hash))
66
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Zernio::PinInboxComment200Response` initialize method"
67
+ end
68
+
69
+ # check to see if the attribute exists and convert string to symbol for hash key
70
+ acceptable_attribute_map = self.class.acceptable_attribute_map
71
+ attributes = attributes.each_with_object({}) { |(k, v), h|
72
+ if (!acceptable_attribute_map.key?(k.to_sym))
73
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Zernio::PinInboxComment200Response`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
74
+ end
75
+ h[k.to_sym] = v
76
+ }
77
+
78
+ if attributes.key?(:'status')
79
+ self.status = attributes[:'status']
80
+ end
81
+
82
+ if attributes.key?(:'comment_id')
83
+ self.comment_id = attributes[:'comment_id']
84
+ end
85
+
86
+ if attributes.key?(:'pinned')
87
+ self.pinned = attributes[:'pinned']
88
+ end
89
+
90
+ if attributes.key?(:'platform')
91
+ self.platform = attributes[:'platform']
92
+ end
93
+ end
94
+
95
+ # Show invalid properties with the reasons. Usually used together with valid?
96
+ # @return Array for valid properties with the reasons
97
+ def list_invalid_properties
98
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
99
+ invalid_properties = Array.new
100
+ invalid_properties
101
+ end
102
+
103
+ # Check to see if the all the properties in the model are valid
104
+ # @return true if the model is valid
105
+ def valid?
106
+ warn '[DEPRECATED] the `valid?` method is obsolete'
107
+ true
108
+ end
109
+
110
+ # Checks equality by comparing each attribute.
111
+ # @param [Object] Object to be compared
112
+ def ==(o)
113
+ return true if self.equal?(o)
114
+ self.class == o.class &&
115
+ status == o.status &&
116
+ comment_id == o.comment_id &&
117
+ pinned == o.pinned &&
118
+ platform == o.platform
119
+ end
120
+
121
+ # @see the `==` method
122
+ # @param [Object] Object to be compared
123
+ def eql?(o)
124
+ self == o
125
+ end
126
+
127
+ # Calculates hash code according to all attributes.
128
+ # @return [Integer] Hash code
129
+ def hash
130
+ [status, comment_id, pinned, platform].hash
131
+ end
132
+
133
+ # Builds the object from hash
134
+ # @param [Hash] attributes Model attributes in the form of hash
135
+ # @return [Object] Returns the model itself
136
+ def self.build_from_hash(attributes)
137
+ return nil unless attributes.is_a?(Hash)
138
+ attributes = attributes.transform_keys(&:to_sym)
139
+ transformed_hash = {}
140
+ openapi_types.each_pair do |key, type|
141
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
142
+ transformed_hash["#{key}"] = nil
143
+ elsif type =~ /\AArray<(.*)>/i
144
+ # check to ensure the input is an array given that the attribute
145
+ # is documented as an array but the input is not
146
+ if attributes[attribute_map[key]].is_a?(Array)
147
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
148
+ end
149
+ elsif !attributes[attribute_map[key]].nil?
150
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
151
+ end
152
+ end
153
+ new(transformed_hash)
154
+ end
155
+
156
+ # Returns the object in the form of hash
157
+ # @return [Hash] Returns the object in the form of hash
158
+ def to_hash
159
+ hash = {}
160
+ self.class.attribute_map.each_pair do |attr, param|
161
+ value = self.send(attr)
162
+ if value.nil?
163
+ is_nullable = self.class.openapi_nullable.include?(attr)
164
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
165
+ end
166
+
167
+ hash[param] = _to_hash(value)
168
+ end
169
+ hash
170
+ end
171
+
172
+ end
173
+
174
+ end
@@ -0,0 +1,165 @@
1
+ =begin
2
+ #Zernio API
3
+
4
+ #API reference for Zernio. Authenticate with a Bearer API key. Base URL: https://zernio.com/api Versioning and deprecation: all endpoints are versioned in the URL path (current version: /v1). Breaking changes only ship in a new path version; existing versions keep working. Deprecated operations are marked 'deprecated: true' in this spec and announced in the changelog (https://zernio.com/changelog) before removal. Errors: every 4xx/5xx response is application/json with a machine-readable 'code' and a human-readable 'error' message (see the ErrorResponse schema).
5
+
6
+ The version of the OpenAPI document: 1.0.4
7
+ Contact: support@zernio.com
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.19.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Zernio
17
+ class PinInboxCommentRequest < ApiModelBase
18
+ # The social account ID
19
+ attr_accessor :account_id
20
+
21
+ # Attribute mapping from ruby-style variable name to JSON key.
22
+ def self.attribute_map
23
+ {
24
+ :'account_id' => :'accountId'
25
+ }
26
+ end
27
+
28
+ # Returns attribute mapping this model knows about
29
+ def self.acceptable_attribute_map
30
+ attribute_map
31
+ end
32
+
33
+ # Returns all the JSON keys this model knows about
34
+ def self.acceptable_attributes
35
+ acceptable_attribute_map.values
36
+ end
37
+
38
+ # Attribute type mapping.
39
+ def self.openapi_types
40
+ {
41
+ :'account_id' => :'String'
42
+ }
43
+ end
44
+
45
+ # List of attributes with nullable: true
46
+ def self.openapi_nullable
47
+ Set.new([
48
+ ])
49
+ end
50
+
51
+ # Initializes the object
52
+ # @param [Hash] attributes Model attributes in the form of hash
53
+ def initialize(attributes = {})
54
+ if (!attributes.is_a?(Hash))
55
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Zernio::PinInboxCommentRequest` initialize method"
56
+ end
57
+
58
+ # check to see if the attribute exists and convert string to symbol for hash key
59
+ acceptable_attribute_map = self.class.acceptable_attribute_map
60
+ attributes = attributes.each_with_object({}) { |(k, v), h|
61
+ if (!acceptable_attribute_map.key?(k.to_sym))
62
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Zernio::PinInboxCommentRequest`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
63
+ end
64
+ h[k.to_sym] = v
65
+ }
66
+
67
+ if attributes.key?(:'account_id')
68
+ self.account_id = attributes[:'account_id']
69
+ else
70
+ self.account_id = nil
71
+ end
72
+ end
73
+
74
+ # Show invalid properties with the reasons. Usually used together with valid?
75
+ # @return Array for valid properties with the reasons
76
+ def list_invalid_properties
77
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
78
+ invalid_properties = Array.new
79
+ if @account_id.nil?
80
+ invalid_properties.push('invalid value for "account_id", account_id cannot be nil.')
81
+ end
82
+
83
+ invalid_properties
84
+ end
85
+
86
+ # Check to see if the all the properties in the model are valid
87
+ # @return true if the model is valid
88
+ def valid?
89
+ warn '[DEPRECATED] the `valid?` method is obsolete'
90
+ return false if @account_id.nil?
91
+ true
92
+ end
93
+
94
+ # Custom attribute writer method with validation
95
+ # @param [Object] account_id Value to be assigned
96
+ def account_id=(account_id)
97
+ if account_id.nil?
98
+ fail ArgumentError, 'account_id cannot be nil'
99
+ end
100
+
101
+ @account_id = account_id
102
+ end
103
+
104
+ # Checks equality by comparing each attribute.
105
+ # @param [Object] Object to be compared
106
+ def ==(o)
107
+ return true if self.equal?(o)
108
+ self.class == o.class &&
109
+ account_id == o.account_id
110
+ end
111
+
112
+ # @see the `==` method
113
+ # @param [Object] Object to be compared
114
+ def eql?(o)
115
+ self == o
116
+ end
117
+
118
+ # Calculates hash code according to all attributes.
119
+ # @return [Integer] Hash code
120
+ def hash
121
+ [account_id].hash
122
+ end
123
+
124
+ # Builds the object from hash
125
+ # @param [Hash] attributes Model attributes in the form of hash
126
+ # @return [Object] Returns the model itself
127
+ def self.build_from_hash(attributes)
128
+ return nil unless attributes.is_a?(Hash)
129
+ attributes = attributes.transform_keys(&:to_sym)
130
+ transformed_hash = {}
131
+ openapi_types.each_pair do |key, type|
132
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
133
+ transformed_hash["#{key}"] = nil
134
+ elsif type =~ /\AArray<(.*)>/i
135
+ # check to ensure the input is an array given that the attribute
136
+ # is documented as an array but the input is not
137
+ if attributes[attribute_map[key]].is_a?(Array)
138
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
139
+ end
140
+ elsif !attributes[attribute_map[key]].nil?
141
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
142
+ end
143
+ end
144
+ new(transformed_hash)
145
+ end
146
+
147
+ # Returns the object in the form of hash
148
+ # @return [Hash] Returns the object in the form of hash
149
+ def to_hash
150
+ hash = {}
151
+ self.class.attribute_map.each_pair do |attr, param|
152
+ value = self.send(attr)
153
+ if value.nil?
154
+ is_nullable = self.class.openapi_nullable.include?(attr)
155
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
156
+ end
157
+
158
+ hash[param] = _to_hash(value)
159
+ end
160
+ hash
161
+ end
162
+
163
+ end
164
+
165
+ end
@@ -21,7 +21,7 @@ module Zernio
21
21
  # Posts inserted or updated in Zernio
22
22
  attr_accessor :posts_synced
23
23
 
24
- # True when no live fetch ran: the post was already stored, or the account was synced within the debounce window
24
+ # True when the account was synced within the debounce window and no live fetch ran.
25
25
  attr_accessor :skipped
26
26
 
27
27
  # Attribute mapping from ruby-style variable name to JSON key.
@@ -19,7 +19,7 @@ module Zernio
19
19
  # When true, sends the post to the TikTok Creator Inbox as a draft instead of publishing immediately. The creator receives an inbox notification to complete posting via TikTok's editing flow. Maps to TikTok API post_mode: \"MEDIA_UPLOAD\" (photos) or the dedicated inbox endpoint (videos). When false or omitted, publishes directly via post_mode: \"DIRECT_POST\". Note: publish_type is not a supported field. Use this field instead.
20
20
  attr_accessor :draft
21
21
 
22
- # One of the values returned by the TikTok creator info API for the account
22
+ # One of the values returned by the TikTok creator info API for the account. Accounts connected through the TikTok for Business app publish videos as public only: a non-public value on a video post is rejected at creation unless draft is true (photo posts keep every level).
23
23
  attr_accessor :privacy_level
24
24
 
25
25
  # Allow comments on the post
@@ -14,7 +14,7 @@ require 'date'
14
14
  require 'time'
15
15
 
16
16
  module Zernio
17
- # Webhook payload for comment received events (Instagram, Facebook, X, YouTube, LinkedIn, Bluesky, Reddit)
17
+ # Webhook payload for comment received events (Instagram, Facebook, X, YouTube, LinkedIn, Bluesky, Reddit, TikTok). TikTok events carry only the author id: the comment.update webhook has no username, picture or owner flag.
18
18
  class WebhookPayloadComment < ApiModelBase
19
19
  # Stable webhook event ID
20
20
  attr_accessor :id
@@ -239,7 +239,7 @@ module Zernio
239
239
  return false if @id.nil?
240
240
  return false if @platform_post_id.nil?
241
241
  return false if @platform.nil?
242
- platform_validator = EnumAttributeValidator.new('String', ["instagram", "facebook", "twitter", "youtube", "linkedin", "bluesky", "reddit"])
242
+ platform_validator = EnumAttributeValidator.new('String', ["instagram", "facebook", "twitter", "youtube", "linkedin", "bluesky", "reddit", "tiktok"])
243
243
  return false unless platform_validator.valid?(@platform)
244
244
  return false if @text.nil?
245
245
  return false if @author.nil?
@@ -271,7 +271,7 @@ module Zernio
271
271
  # Custom attribute writer method checking allowed values (enum).
272
272
  # @param [Object] platform Object to be assigned
273
273
  def platform=(platform)
274
- validator = EnumAttributeValidator.new('String', ["instagram", "facebook", "twitter", "youtube", "linkedin", "bluesky", "reddit"])
274
+ validator = EnumAttributeValidator.new('String', ["instagram", "facebook", "twitter", "youtube", "linkedin", "bluesky", "reddit", "tiktok"])
275
275
  unless validator.valid?(platform)
276
276
  fail ArgumentError, "invalid value for \"platform\", must be one of #{validator.allowable_values}."
277
277
  end
@@ -11,5 +11,5 @@ Generator version: 7.19.0
11
11
  =end
12
12
 
13
13
  module Zernio
14
- VERSION = '0.0.913'
14
+ VERSION = '0.0.914'
15
15
  end
data/lib/zernio-sdk.rb CHANGED
@@ -1281,6 +1281,8 @@ require 'zernio-sdk/models/pause_workflow200_response'
1281
1281
  require 'zernio-sdk/models/pending'
1282
1282
  require 'zernio-sdk/models/phone_number_stock_watch'
1283
1283
  require 'zernio-sdk/models/pin_discord_message200_response'
1284
+ require 'zernio-sdk/models/pin_inbox_comment200_response'
1285
+ require 'zernio-sdk/models/pin_inbox_comment_request'
1284
1286
  require 'zernio-sdk/models/pinterest_platform_data'
1285
1287
  require 'zernio-sdk/models/platform_analytics'
1286
1288
  require 'zernio-sdk/models/platform_target'
data/openapi.yaml CHANGED
@@ -3144,7 +3144,7 @@ components:
3144
3144
  description: 'UTC time at which Zernio generated this event (set once when the event payload is built, before delivery is queued).'
3145
3145
  WebhookPayloadComment:
3146
3146
  type: object
3147
- description: Webhook payload for comment received events (Instagram, Facebook, X, YouTube, LinkedIn, Bluesky, Reddit)
3147
+ description: 'Webhook payload for comment received events (Instagram, Facebook, X, YouTube, LinkedIn, Bluesky, Reddit, TikTok). TikTok events carry only the author id: the comment.update webhook has no username, picture or owner flag.'
3148
3148
  required: [id, event, comment, post, account, timestamp]
3149
3149
  properties:
3150
3150
  id:
@@ -3168,7 +3168,7 @@ components:
3168
3168
  description: Platform's post ID
3169
3169
  platform:
3170
3170
  type: string
3171
- enum: [instagram, facebook, twitter, youtube, linkedin, bluesky, reddit]
3171
+ enum: [instagram, facebook, twitter, youtube, linkedin, bluesky, reddit, tiktok]
3172
3172
  text:
3173
3173
  type: string
3174
3174
  description: Comment text content
@@ -6764,7 +6764,7 @@ components:
6764
6764
  Note: publish_type is not a supported field. Use this field instead.
6765
6765
  privacyLevel:
6766
6766
  type: string
6767
- description: One of the values returned by the TikTok creator info API for the account
6767
+ description: 'One of the values returned by the TikTok creator info API for the account. Accounts connected through the TikTok for Business app publish videos as public only: a non-public value on a video post is rejected at creation unless draft is true (photo posts keep every level).'
6768
6768
  allowComment:
6769
6769
  type: boolean
6770
6770
  description: Allow comments on the post
@@ -16789,6 +16789,7 @@ paths:
16789
16789
  x-resource-group: "publishing"
16790
16790
  operationId: syncExternalPosts
16791
16791
  tags: [Analytics]
16792
+ x-platforms: [instagram, facebook, tiktok, youtube, twitter, threads, pinterest, reddit, bluesky, googlebusiness, linkedin]
16792
16793
  summary: Sync an external post
16793
16794
  description: |
16794
16795
  Fetch an account's latest external posts (published directly on the platform, not through Zernio) on demand, so a newly published post is retrievable within seconds instead of waiting for the background sync (which refreshes each account at most every ~90 minutes).
@@ -16796,8 +16797,9 @@ paths:
16796
16797
  Primary use case: verifying a submitted post. When a user publishes on the platform and immediately pastes the post URL into your app, call this with `accountId` plus `url` (or `postId`) to confirm the post exists and return its metadata.
16797
16798
 
16798
16799
  Behavior:
16799
- - We check our stored copy first and return immediately if the post is already known (no platform call).
16800
- - Otherwise we fetch the account's latest posts live from the platform, then match and return the submitted post.
16800
+ - Account access and connection state are checked before any platform call, including requests inside the debounce window.
16801
+ - Inactive accounts or accounts marked `needsReconnection` return `409` with code `ads_connection_required`. Stop scheduled retries for that account until it is reconnected, then read `GET /v1/accounts` for its current account ID.
16802
+ - For connected accounts, we fetch the latest posts live from the platform, then match and return the submitted post.
16801
16803
  - Requests are debounced per account (~15s): if the account was synced inside that window, the live fetch is skipped.
16802
16804
 
16803
16805
  `accountId` is required, because a post URL or id alone cannot be resolved to an account, and the account must be connected to Zernio (we use its token to read the platform). Supported for every platform with a listing API (Instagram, Facebook, TikTok, YouTube, X, Threads, Pinterest, Reddit, Bluesky, Google Business Profile, and LinkedIn organization accounts).
@@ -16838,7 +16840,7 @@ paths:
16838
16840
  properties:
16839
16841
  postsFound: { type: integer, description: Posts returned by the platform listing during the on-demand sync }
16840
16842
  postsSynced: { type: integer, description: Posts inserted or updated in Zernio }
16841
- skipped: { type: boolean, description: "True when no live fetch ran: the post was already stored, or the account was synced within the debounce window" }
16843
+ skipped: { type: boolean, description: "True when the account was synced within the debounce window and no live fetch ran." }
16842
16844
  found:
16843
16845
  type: boolean
16844
16846
  description: "Present only when a locator (`url`/`postId`) was provided: whether the post was found."
@@ -16867,7 +16869,18 @@ paths:
16867
16869
  '503': { $ref: '#/components/responses/TemporarilyUnavailable' }
16868
16870
  '502': { $ref: '#/components/responses/UpstreamFailure' }
16869
16871
  '401': { description: 'The platform authorization has expired. Reconnect the account.' }
16870
- '403': { description: 'The account is inactive or the platform denied access.' }
16872
+ '403': { description: 'The API key lacks access to this account or the platform denied access.' }
16873
+ '409':
16874
+ description: 'The account is inactive or needs reconnection. Stop scheduled retries until it is reconnected.'
16875
+ content:
16876
+ application/json:
16877
+ schema:
16878
+ $ref: '#/components/schemas/ErrorResponse'
16879
+ example:
16880
+ error: 'This account needs reconnection. Reconnect the account, then read GET /v1/accounts for its current account ID before retrying.'
16881
+ type: invalid_request_error
16882
+ code: ads_connection_required
16883
+ param: accountId
16871
16884
 
16872
16885
  /v1/posts/{postId}:
16873
16886
  get:
@@ -31015,6 +31028,11 @@ paths:
31015
31028
  window. Do not poll this endpoint for real-time updates: subscribe to the
31016
31029
  `comment.received` webhook, which delivers new comments as they arrive. Your own
31017
31030
  writes (creating, replying to, or deleting a comment) refresh the cache immediately.
31031
+
31032
+ TikTok is served for accounts connected through the TikTok for Business app: `postId`
31033
+ is the TikTok video id, each top-level comment carries up to three inline replies, and
31034
+ `commentId` pages the full reply list of one comment. Developer-app TikTok accounts
31035
+ return 400 with code `PLATFORM_LIMITATION`.
31018
31036
  tags: [Comments]
31019
31037
  security: [{ bearerAuth: [] }]
31020
31038
  parameters:
@@ -31042,7 +31060,7 @@ paths:
31042
31060
  - name: commentId
31043
31061
  in: query
31044
31062
  schema: { type: string }
31045
- description: (Reddit only) Get replies to a specific comment
31063
+ description: (Reddit and TikTok only) Get replies to a specific comment
31046
31064
  responses:
31047
31065
  '200':
31048
31066
  description: Comments for the post
@@ -31411,7 +31429,8 @@ paths:
31411
31429
  operationId: hideInboxComment
31412
31430
  summary: Hide comment
31413
31431
  description: |
31414
- Hide a comment on a post. Supported by Facebook, Instagram, Threads, and X.
31432
+ Hide a comment on a post. Supported by Facebook, Instagram, Threads, X, and TikTok
31433
+ (accounts connected through the TikTok for Business app).
31415
31434
  Hidden comments are only visible to the commenter and page admin.
31416
31435
  For X, the reply must belong to a conversation started by the authenticated user.
31417
31436
  tags: [Comments]
@@ -31456,7 +31475,8 @@ paths:
31456
31475
  operationId: unhideInboxComment
31457
31476
  summary: Unhide comment
31458
31477
  description: |
31459
- Unhide a previously hidden comment. Supported by Facebook, Instagram, Threads, and X.
31478
+ Unhide a previously hidden comment. Supported by Facebook, Instagram, Threads, X, and
31479
+ TikTok (accounts connected through the TikTok for Business app).
31460
31480
  tags: [Comments]
31461
31481
  security: [{ bearerAuth: [] }]
31462
31482
  parameters:
@@ -31490,6 +31510,89 @@ paths:
31490
31510
  '403':
31491
31511
  description: Inbox addon required
31492
31512
 
31513
+ /v1/inbox/comments/{postId}/{commentId}/pin:
31514
+ post:
31515
+ x-resource-group: "engagement"
31516
+ operationId: pinInboxComment
31517
+ summary: Pin comment
31518
+ description: |
31519
+ Pin a top-level comment to the top of a post's comment section. TikTok accounts
31520
+ connected through the TikTok for Business app only; every other platform returns 400.
31521
+ tags: [Comments]
31522
+ security: [{ bearerAuth: [] }]
31523
+ parameters:
31524
+ - name: postId
31525
+ in: path
31526
+ required: true
31527
+ schema: { type: string }
31528
+ - name: commentId
31529
+ in: path
31530
+ required: true
31531
+ schema: { type: string }
31532
+ requestBody:
31533
+ required: true
31534
+ content:
31535
+ application/json:
31536
+ schema:
31537
+ type: object
31538
+ required: [accountId]
31539
+ properties:
31540
+ accountId: { type: string, description: The social account ID }
31541
+ responses:
31542
+ '200':
31543
+ description: Comment pinned
31544
+ content:
31545
+ application/json:
31546
+ schema:
31547
+ type: object
31548
+ properties:
31549
+ status: { type: string }
31550
+ commentId: { type: string }
31551
+ pinned: { type: boolean }
31552
+ platform: { type: string }
31553
+ '400': { $ref: '#/components/responses/BadRequest' }
31554
+ '401': { $ref: '#/components/responses/Unauthorized' }
31555
+ '403':
31556
+ description: Inbox addon required
31557
+ delete:
31558
+ x-resource-group: "engagement"
31559
+ operationId: unpinInboxComment
31560
+ summary: Unpin comment
31561
+ description: |
31562
+ Unpin a previously pinned comment. TikTok accounts connected through the TikTok for
31563
+ Business app only.
31564
+ tags: [Comments]
31565
+ security: [{ bearerAuth: [] }]
31566
+ parameters:
31567
+ - name: postId
31568
+ in: path
31569
+ required: true
31570
+ schema: { type: string }
31571
+ - name: commentId
31572
+ in: path
31573
+ required: true
31574
+ schema: { type: string }
31575
+ - name: accountId
31576
+ in: query
31577
+ required: true
31578
+ schema: { type: string }
31579
+ responses:
31580
+ '200':
31581
+ description: Comment unpinned
31582
+ content:
31583
+ application/json:
31584
+ schema:
31585
+ type: object
31586
+ properties:
31587
+ status: { type: string }
31588
+ commentId: { type: string }
31589
+ pinned: { type: boolean }
31590
+ platform: { type: string }
31591
+ '400': { $ref: '#/components/responses/BadRequest' }
31592
+ '401': { $ref: '#/components/responses/Unauthorized' }
31593
+ '403':
31594
+ description: Inbox addon required
31595
+
31493
31596
  /v1/inbox/comments/{postId}/{commentId}/like:
31494
31597
  post:
31495
31598
  x-resource-group: "engagement"
@@ -422,7 +422,7 @@ describe 'AnalyticsApi' do
422
422
 
423
423
  # unit tests for sync_external_posts
424
424
  # Sync an external post
425
- # Fetch an account&#39;s latest external posts (published directly on the platform, not through Zernio) on demand, so a newly published post is retrievable within seconds instead of waiting for the background sync (which refreshes each account at most every ~90 minutes). Primary use case: verifying a submitted post. When a user publishes on the platform and immediately pastes the post URL into your app, call this with &#x60;accountId&#x60; plus &#x60;url&#x60; (or &#x60;postId&#x60;) to confirm the post exists and return its metadata. Behavior: - We check our stored copy first and return immediately if the post is already known (no platform call). - Otherwise we fetch the account&#39;s latest posts live from the platform, then match and return the submitted post. - Requests are debounced per account (~15s): if the account was synced inside that window, the live fetch is skipped. &#x60;accountId&#x60; is required, because a post URL or id alone cannot be resolved to an account, and the account must be connected to Zernio (we use its token to read the platform). Supported for every platform with a listing API (Instagram, Facebook, TikTok, YouTube, X, Threads, Pinterest, Reddit, Bluesky, Google Business Profile, and LinkedIn organization accounts). LinkedIn personal profiles: LinkedIn has no listing API for personal profiles, so a &#x60;url&#x60; is REQUIRED and imports that single post. Pass any LinkedIn post URL (&#x60;linkedin.com/posts/…&#x60;, &#x60;linkedin.com/feed/update/urn:li:activity:…&#x60;) or a &#x60;urn:li:share:…&#x60; / &#x60;urn:li:ugcPost:…&#x60; URN. Works for posts published outside Zernio and before the account was connected, any age; the post must be authored by the connected member. Imported posts return full analytics (impressions, reach, reactions, comments, reshares, saves) and keep refreshing on the background analytics cycle, but carry no content/media (LinkedIn does not expose them for personal profiles). &#x60;url&#x60; accepts any format the platform uses (e.g. &#x60;instagram.com/p/…&#x60;, &#x60;instagram.com/reel/…&#x60;, &#x60;youtu.be/…&#x60;, &#x60;youtube.com/shorts/…&#x60;, &#x60;tiktok.com/@user/video/…&#x60;, &#x60;vm.tiktok.com&#x60; short links, &#x60;pinterest.com/pin/…&#x60; on any regional domain, and &#x60;pin.it&#x60; short links). Pass &#x60;postId&#x60; (the platform media/video/pin id) as an alternative locator. Note: post-level analytics (reach, impressions) still carry the platform&#39;s own delay (e.g. ~24h on Instagram). This endpoint confirms the post exists and returns its metadata plus basic engagement (likes, comments), not delayed insights.
425
+ # Fetch an account&#39;s latest external posts (published directly on the platform, not through Zernio) on demand, so a newly published post is retrievable within seconds instead of waiting for the background sync (which refreshes each account at most every ~90 minutes). Primary use case: verifying a submitted post. When a user publishes on the platform and immediately pastes the post URL into your app, call this with &#x60;accountId&#x60; plus &#x60;url&#x60; (or &#x60;postId&#x60;) to confirm the post exists and return its metadata. Behavior: - Account access and connection state are checked before any platform call, including requests inside the debounce window. - Inactive accounts or accounts marked &#x60;needsReconnection&#x60; return &#x60;409&#x60; with code &#x60;ads_connection_required&#x60;. Stop scheduled retries for that account until it is reconnected, then read &#x60;GET /v1/accounts&#x60; for its current account ID. - For connected accounts, we fetch the latest posts live from the platform, then match and return the submitted post. - Requests are debounced per account (~15s): if the account was synced inside that window, the live fetch is skipped. &#x60;accountId&#x60; is required, because a post URL or id alone cannot be resolved to an account, and the account must be connected to Zernio (we use its token to read the platform). Supported for every platform with a listing API (Instagram, Facebook, TikTok, YouTube, X, Threads, Pinterest, Reddit, Bluesky, Google Business Profile, and LinkedIn organization accounts). LinkedIn personal profiles: LinkedIn has no listing API for personal profiles, so a &#x60;url&#x60; is REQUIRED and imports that single post. Pass any LinkedIn post URL (&#x60;linkedin.com/posts/…&#x60;, &#x60;linkedin.com/feed/update/urn:li:activity:…&#x60;) or a &#x60;urn:li:share:…&#x60; / &#x60;urn:li:ugcPost:…&#x60; URN. Works for posts published outside Zernio and before the account was connected, any age; the post must be authored by the connected member. Imported posts return full analytics (impressions, reach, reactions, comments, reshares, saves) and keep refreshing on the background analytics cycle, but carry no content/media (LinkedIn does not expose them for personal profiles). &#x60;url&#x60; accepts any format the platform uses (e.g. &#x60;instagram.com/p/…&#x60;, &#x60;instagram.com/reel/…&#x60;, &#x60;youtu.be/…&#x60;, &#x60;youtube.com/shorts/…&#x60;, &#x60;tiktok.com/@user/video/…&#x60;, &#x60;vm.tiktok.com&#x60; short links, &#x60;pinterest.com/pin/…&#x60; on any regional domain, and &#x60;pin.it&#x60; short links). Pass &#x60;postId&#x60; (the platform media/video/pin id) as an alternative locator. Note: post-level analytics (reach, impressions) still carry the platform&#39;s own delay (e.g. ~24h on Instagram). This endpoint confirms the post exists and returns its metadata plus basic engagement (likes, comments), not delayed insights.
426
426
  # @param sync_external_posts_request
427
427
  # @param [Hash] opts the optional parameters
428
428
  # @return [SyncExternalPosts200Response]