omnisocials 0.2.0 → 0.4.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.
- checksums.yaml +4 -4
- data/README.md +61 -0
- data/lib/omnisocials/resources/inbox.rb +14 -4
- data/lib/omnisocials/resources/posts.rb +28 -10
- data/lib/omnisocials/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a8be79cfb8525cbb823f24a4a34d6cb3d51b193d864db80cc190bc0a7db45a18
|
|
4
|
+
data.tar.gz: ed95b24b6e722f29e9c7e94e9d4506c69dece3579f9e609966fa999d5d1893bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2138c0350aea5e6c3059bf5d71bc9cd050441ac11b8846d01d55f9c6bd88c83488cd4e47b5c17ba8e298f98c01d75e53dcf1e54845a89a2c92553f4e896a9386
|
|
7
|
+
data.tar.gz: 10177239235e7dcd623615ed273c4171b81c2819de790bdc636ff495a1dd3b177cc18011b4cf9ac67a1162358d711d927d38a07c7a00ed9d672a0fe551dc524d
|
data/README.md
CHANGED
|
@@ -143,6 +143,26 @@ end
|
|
|
143
143
|
|
|
144
144
|
From `enforce_from` (2026-08-14) the balance is checked at publish time, but credits are only deducted after the post successfully publishes (a failed publish is never charged). If the balance can't cover it, only the X target fails (other platforms publish normally); top up in the dashboard under Settings -> Organisation -> Billing -> Credits, then call `posts.retry`. Posts without links, analytics, and media on X stay free. There is no API endpoint for credits — they are managed in the dashboard.
|
|
145
145
|
|
|
146
|
+
Separately, from 2026-08-14 `posts.create` / `posts.update` / `posts.publish` on X can refuse the request itself, up front, with a `402` and error code `x_credits_insufficient` (`error.details` carries `credits_required`, `credits_balance`, and `credits_reserved`) when reserving this post's cost would push the company's total reserved credits past its balance:
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
begin
|
|
150
|
+
client.posts.create(
|
|
151
|
+
content: "Read the full story: https://example.com/post",
|
|
152
|
+
channels: ["x"],
|
|
153
|
+
scheduled_at: "2026-08-20T09:00:00Z"
|
|
154
|
+
)
|
|
155
|
+
rescue OmniSocials::APIError => e
|
|
156
|
+
if e.code == "x_credits_insufficient"
|
|
157
|
+
puts "Not enough reserved credits: #{e.body["error"]["details"]}"
|
|
158
|
+
else
|
|
159
|
+
raise
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Drafts are never gated, and posts scheduled to publish before 2026-08-14 are never gated either.
|
|
165
|
+
|
|
146
166
|
### Other post operations
|
|
147
167
|
|
|
148
168
|
```ruby
|
|
@@ -310,6 +330,47 @@ client.posts.create(
|
|
|
310
330
|
)
|
|
311
331
|
```
|
|
312
332
|
|
|
333
|
+
## Inbox
|
|
334
|
+
|
|
335
|
+
Read and reply to social inbox conversations (DMs, comments, mentions) across connected platforms. Requires an API key with the opt-in `inbox:read` / `inbox:write` scopes. The list endpoints are cursor-paginated (unlike the offset pagination used elsewhere): page while `pagination["has_more"]` is true by passing the previous response's `pagination["next_cursor"]` as `cursor`.
|
|
336
|
+
|
|
337
|
+
```ruby
|
|
338
|
+
conversations = client.inbox.list_conversations(platform: "instagram", unread: true, limit: 20)
|
|
339
|
+
conversations["data"].each do |conversation|
|
|
340
|
+
puts "#{conversation["platform"]}: #{conversation["preview"]}"
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
conversation_id = conversations["data"][0]["id"]
|
|
344
|
+
messages = client.inbox.get_messages(conversation_id)
|
|
345
|
+
messages["data"].each do |message|
|
|
346
|
+
puts "#{message["direction"]}: #{message["text"]}" # direction is "incoming" or "outgoing"
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
client.inbox.mark_read(conversation_id)
|
|
350
|
+
client.inbox.reply(conversation_id, text: "Thanks for reaching out!")
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
`platform` accepts `"instagram"`, `"facebook"`, `"linkedin"`, `"tiktok"`, or `"x"`; `type` accepts `"dm"`, `"comment"`, or `"mention"`. TikTok replies are comments only and capped at 150 characters. Conversation ids are URL-encoded for you, so pass them exactly as returned - LinkedIn ids contain `":"` and `"()"` (e.g. `"linkedin_comment_urn:li:activity:123"`).
|
|
354
|
+
|
|
355
|
+
Replying to an X DM costs 2 prepaid credits, debited from the company balance before the send and automatically refunded if the send fails:
|
|
356
|
+
|
|
357
|
+
```ruby
|
|
358
|
+
begin
|
|
359
|
+
client.inbox.reply(conversation_id, text: "On it, thanks!")
|
|
360
|
+
rescue OmniSocials::APIError => e
|
|
361
|
+
case e.code
|
|
362
|
+
when "insufficient_credits"
|
|
363
|
+
puts "Not enough credits to send this reply (need 2)."
|
|
364
|
+
when "x_inbox_suspended"
|
|
365
|
+
puts "X inbox is suspended - top up and re-enable it in the dashboard."
|
|
366
|
+
else
|
|
367
|
+
raise
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
`x_inbox_suspended` fires once a workspace's X inbox has auto-suspended after its credit balance hit zero; topping up and re-enabling it in the dashboard resumes delivery, but DMs that arrived while suspended are not recovered.
|
|
373
|
+
|
|
313
374
|
## Webhooks
|
|
314
375
|
|
|
315
376
|
Subscribe to `post.scheduled`, `post.published`, and `post.failed` events:
|
|
@@ -23,9 +23,10 @@ module OmniSocials
|
|
|
23
23
|
# GET /inbox/conversations - list conversations, newest activity first.
|
|
24
24
|
#
|
|
25
25
|
# All filters are optional: platform ("instagram", "facebook",
|
|
26
|
-
# "linkedin"), type ("dm", "comment", "mention"),
|
|
27
|
-
# conversations with unread messages), limit (1-100), and
|
|
28
|
-
# opaque cursor from a previous response's
|
|
26
|
+
# "linkedin", "tiktok", "x"), type ("dm", "comment", "mention"),
|
|
27
|
+
# unread (only conversations with unread messages), limit (1-100), and
|
|
28
|
+
# cursor (an opaque cursor from a previous response's
|
|
29
|
+
# pagination["next_cursor"]).
|
|
29
30
|
def list_conversations(platform: nil, type: nil, unread: nil, limit: nil, cursor: nil)
|
|
30
31
|
@client.request(
|
|
31
32
|
"GET", "/inbox/conversations",
|
|
@@ -59,7 +60,16 @@ module OmniSocials
|
|
|
59
60
|
#
|
|
60
61
|
# `text` is required. Optionally attach a single media asset by public
|
|
61
62
|
# URL with `attachment_url` plus `attachment_type` ("image", "video",
|
|
62
|
-
# "audio", or "file"). Returns the created
|
|
63
|
+
# "audio", or "file"). Returns the created outgoing message.
|
|
64
|
+
#
|
|
65
|
+
# Replying to an X DM costs 2 prepaid credits, debited from the
|
|
66
|
+
# company balance before the send and automatically refunded if the
|
|
67
|
+
# send fails. Two 402 error codes are specific to this call:
|
|
68
|
+
# "insufficient_credits" when the balance can't cover the 2 credits,
|
|
69
|
+
# and "x_inbox_suspended" when the workspace's X inbox was
|
|
70
|
+
# auto-suspended after the balance hit zero (top up and re-enable it
|
|
71
|
+
# in the dashboard to resume; DMs that arrived while suspended are
|
|
72
|
+
# not recovered).
|
|
63
73
|
def reply(conversation_id, text:, attachment_url: nil, attachment_type: nil)
|
|
64
74
|
body = Internal.drop_nil(
|
|
65
75
|
{
|
|
@@ -18,7 +18,9 @@ module OmniSocials
|
|
|
18
18
|
@client = client
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
# GET /posts - list posts (status: draft, scheduled,
|
|
21
|
+
# GET /posts - list posts (status: draft, in_approval, scheduled, posting,
|
|
22
|
+
# posted, failed, warning; in_approval = waiting for a reviewer in an
|
|
23
|
+
# approval workflow).
|
|
22
24
|
def list(status: nil, limit: nil, offset: nil)
|
|
23
25
|
@client.request(
|
|
24
26
|
"GET", "/posts",
|
|
@@ -57,6 +59,14 @@ module OmniSocials
|
|
|
57
59
|
# and credits_balance: X's link-post fee is passed through as prepaid
|
|
58
60
|
# credits, debited at publish time (from 2026-08-14). Credits are
|
|
59
61
|
# managed in the dashboard, not the API.
|
|
62
|
+
#
|
|
63
|
+
# Separately, from 2026-08-14 this call (and #update / #publish) can
|
|
64
|
+
# refuse an X link post up front with a 402 and error code
|
|
65
|
+
# "x_credits_insufficient" (details: credits_required, credits_balance,
|
|
66
|
+
# credits_reserved) when reserving this post's cost would push the
|
|
67
|
+
# company's total reserved credits past its balance. Drafts are never
|
|
68
|
+
# gated, and posts scheduled to publish before 2026-08-14 are never
|
|
69
|
+
# gated either.
|
|
60
70
|
def create(content:, channels: nil, scheduled_at: nil, media_ids: nil,
|
|
61
71
|
media_urls: nil, type: nil, source: nil, link_url: nil,
|
|
62
72
|
link_title: nil, link_description: nil, link_thumbnail_url: nil,
|
|
@@ -65,7 +75,7 @@ module OmniSocials
|
|
|
65
75
|
hashtag_platforms: nil, pinterest: nil, youtube: nil,
|
|
66
76
|
instagram: nil, facebook: nil, linkedin: nil,
|
|
67
77
|
linkedin_page: nil, tiktok: nil, x: nil, bluesky: nil,
|
|
68
|
-
mastodon: nil, google_business: nil)
|
|
78
|
+
mastodon: nil, google_business: nil, linkedin_poll: nil)
|
|
69
79
|
body = create_body(
|
|
70
80
|
content: content, channels: channels, scheduled_at: scheduled_at,
|
|
71
81
|
media_ids: media_ids, media_urls: media_urls, type: type,
|
|
@@ -78,13 +88,14 @@ module OmniSocials
|
|
|
78
88
|
youtube: youtube, instagram: instagram, facebook: facebook,
|
|
79
89
|
linkedin: linkedin, linkedin_page: linkedin_page, tiktok: tiktok,
|
|
80
90
|
x: x, bluesky: bluesky, mastodon: mastodon,
|
|
81
|
-
google_business: google_business
|
|
91
|
+
google_business: google_business, linkedin_poll: linkedin_poll
|
|
82
92
|
)
|
|
83
93
|
@client.request("POST", "/posts/create", json: body)
|
|
84
94
|
end
|
|
85
95
|
|
|
86
96
|
# POST /posts/create-and-publish - create and publish immediately.
|
|
87
|
-
# See #create for the "warnings" array
|
|
97
|
+
# See #create for the "warnings" array and the 402
|
|
98
|
+
# "x_credits_insufficient" credit gate on X link posts.
|
|
88
99
|
def create_and_publish(content:, channels: nil, media_ids: nil,
|
|
89
100
|
media_urls: nil, type: nil, source: nil,
|
|
90
101
|
link_url: nil, link_title: nil, link_description: nil,
|
|
@@ -95,7 +106,7 @@ module OmniSocials
|
|
|
95
106
|
pinterest: nil, youtube: nil, instagram: nil,
|
|
96
107
|
facebook: nil, linkedin: nil, linkedin_page: nil,
|
|
97
108
|
tiktok: nil, x: nil, bluesky: nil, mastodon: nil,
|
|
98
|
-
google_business: nil)
|
|
109
|
+
google_business: nil, linkedin_poll: nil)
|
|
99
110
|
body = create_body(
|
|
100
111
|
content: content, channels: channels, scheduled_at: nil,
|
|
101
112
|
media_ids: media_ids, media_urls: media_urls, type: type,
|
|
@@ -108,7 +119,7 @@ module OmniSocials
|
|
|
108
119
|
youtube: youtube, instagram: instagram, facebook: facebook,
|
|
109
120
|
linkedin: linkedin, linkedin_page: linkedin_page, tiktok: tiktok,
|
|
110
121
|
x: x, bluesky: bluesky, mastodon: mastodon,
|
|
111
|
-
google_business: google_business
|
|
122
|
+
google_business: google_business, linkedin_poll: linkedin_poll
|
|
112
123
|
)
|
|
113
124
|
@client.request("POST", "/posts/create-and-publish", json: body)
|
|
114
125
|
end
|
|
@@ -119,12 +130,15 @@ module OmniSocials
|
|
|
119
130
|
# x: { "thread_parts" => nil } still clears an X thread (reverts the
|
|
120
131
|
# post to single-tweet mode). The same applies to bluesky and mastodon
|
|
121
132
|
# thread parts.
|
|
133
|
+
#
|
|
134
|
+
# See #create for the 402 "x_credits_insufficient" credit gate that
|
|
135
|
+
# can also refuse an update to a scheduled X link post.
|
|
122
136
|
def update(post_id, content: nil, scheduled_at: nil, channels: nil,
|
|
123
137
|
media_ids: nil, media_urls: nil, type: nil, location_id: nil,
|
|
124
138
|
collaborators: nil, user_tags: nil, pinterest: nil,
|
|
125
139
|
youtube: nil, instagram: nil, facebook: nil, linkedin: nil,
|
|
126
140
|
linkedin_page: nil, tiktok: nil, x: nil, bluesky: nil,
|
|
127
|
-
mastodon: nil, google_business: nil)
|
|
141
|
+
mastodon: nil, google_business: nil, linkedin_poll: nil)
|
|
128
142
|
body = Internal.drop_nil(
|
|
129
143
|
{
|
|
130
144
|
"content" => content,
|
|
@@ -146,7 +160,8 @@ module OmniSocials
|
|
|
146
160
|
"x" => x,
|
|
147
161
|
"bluesky" => bluesky,
|
|
148
162
|
"mastodon" => mastodon,
|
|
149
|
-
"google_business" => google_business
|
|
163
|
+
"google_business" => google_business,
|
|
164
|
+
"linkedin_poll" => linkedin_poll
|
|
150
165
|
}
|
|
151
166
|
)
|
|
152
167
|
@client.request("PATCH", "/posts/#{post_id}", json: body)
|
|
@@ -158,6 +173,8 @@ module OmniSocials
|
|
|
158
173
|
end
|
|
159
174
|
|
|
160
175
|
# POST /posts/{id}/publish - publish a draft or scheduled post now.
|
|
176
|
+
# See #create for the 402 "x_credits_insufficient" credit gate that
|
|
177
|
+
# can also refuse publishing a scheduled X link post.
|
|
161
178
|
def publish(post_id)
|
|
162
179
|
@client.request("POST", "/posts/#{post_id}/publish")
|
|
163
180
|
end
|
|
@@ -182,7 +199,7 @@ module OmniSocials
|
|
|
182
199
|
hashtag_set_id:, hashtag_placement:, hashtag_platforms:,
|
|
183
200
|
pinterest:, youtube:, instagram:, facebook:, linkedin:,
|
|
184
201
|
linkedin_page:, tiktok:, x:, bluesky:, mastodon:,
|
|
185
|
-
google_business:)
|
|
202
|
+
google_business:, linkedin_poll:)
|
|
186
203
|
Internal.drop_nil(
|
|
187
204
|
{
|
|
188
205
|
"content" => content,
|
|
@@ -213,7 +230,8 @@ module OmniSocials
|
|
|
213
230
|
"x" => x,
|
|
214
231
|
"bluesky" => bluesky,
|
|
215
232
|
"mastodon" => mastodon,
|
|
216
|
-
"google_business" => google_business
|
|
233
|
+
"google_business" => google_business,
|
|
234
|
+
"linkedin_poll" => linkedin_poll
|
|
217
235
|
}
|
|
218
236
|
)
|
|
219
237
|
end
|
data/lib/omnisocials/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omnisocials
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- OmniSocials
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Schedule and publish social media posts, upload media, and read analytics
|
|
14
14
|
across Instagram, Facebook, LinkedIn, YouTube, TikTok, X, Pinterest, Bluesky, Threads,
|