blueticks 1.1.1 → 2.0.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/CHANGELOG.md +41 -0
- data/lib/blueticks/client.rb +27 -5
- data/lib/blueticks/resources/account.rb +2 -2
- data/lib/blueticks/resources/audiences.rb +31 -22
- data/lib/blueticks/resources/campaigns.rb +28 -23
- data/lib/blueticks/resources/chats.rb +37 -86
- data/lib/blueticks/resources/contacts.rb +18 -11
- data/lib/blueticks/resources/engines.rb +12 -19
- data/lib/blueticks/resources/groups.rb +54 -28
- data/lib/blueticks/resources/messages.rb +110 -31
- data/lib/blueticks/resources/newsletters.rb +43 -0
- data/lib/blueticks/resources/ping.rb +6 -3
- data/lib/blueticks/resources/scheduled_messages.rb +74 -30
- data/lib/blueticks/resources/suno.rb +56 -0
- data/lib/blueticks/resources/utils.rb +3 -13
- data/lib/blueticks/resources/webhooks.rb +21 -20
- data/lib/blueticks/types/account.rb +2 -1
- data/lib/blueticks/types/audiences.rb +15 -9
- data/lib/blueticks/types/campaigns.rb +13 -12
- data/lib/blueticks/types/chats.rb +19 -71
- data/lib/blueticks/types/contacts.rb +6 -7
- data/lib/blueticks/types/deleted_resource.rb +14 -0
- data/lib/blueticks/types/engines.rb +9 -8
- data/lib/blueticks/types/groups.rb +22 -6
- data/lib/blueticks/types/messages.rb +124 -11
- data/lib/blueticks/types/newsletter.rb +33 -0
- data/lib/blueticks/types/ok_result.rb +13 -0
- data/lib/blueticks/types/paginated.rb +70 -0
- data/lib/blueticks/types/ping.rb +11 -3
- data/lib/blueticks/types/scheduled_messages.rb +28 -14
- data/lib/blueticks/types/suno.rb +42 -0
- data/lib/blueticks/types/utils.rb +5 -12
- data/lib/blueticks/types/webhooks.rb +13 -11
- data/lib/blueticks/version.rb +1 -1
- data/lib/blueticks.rb +2 -2
- metadata +8 -1
|
@@ -2,64 +2,90 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
4
|
require_relative "../types/groups"
|
|
5
|
+
require_relative "../types/paginated"
|
|
5
6
|
|
|
6
7
|
module Blueticks
|
|
7
8
|
module Resources
|
|
8
9
|
class GroupsResource < BaseResource
|
|
10
|
+
# List groups.
|
|
11
|
+
#
|
|
12
|
+
# List the groups the connected WhatsApp engine sees. Offset-paginated
|
|
13
|
+
# (GroupListItem rows), with an optional case-insensitive name search via
|
|
14
|
+
# `search_token`.
|
|
15
|
+
def list(search_token: nil, include_archive: nil, skip: nil, limit: nil)
|
|
16
|
+
params = {}
|
|
17
|
+
params["searchToken"] = search_token unless search_token.nil?
|
|
18
|
+
params["includeArchive"] = include_archive unless include_archive.nil?
|
|
19
|
+
params["skip"] = skip unless skip.nil?
|
|
20
|
+
params["limit"] = limit unless limit.nil?
|
|
21
|
+
env = client.request("GET", "/v1/groups", params: params.empty? ? nil : params)
|
|
22
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::GroupListItem)
|
|
23
|
+
end
|
|
24
|
+
|
|
9
25
|
# Create a new group with an initial participant list.
|
|
10
26
|
def create(name:, participants:)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Types::Group.from_hash(data)
|
|
27
|
+
env = client.request("POST", "/v1/groups",
|
|
28
|
+
body: { "name" => name, "participants" => participants })
|
|
29
|
+
Types::Group.from_hash(env && env["data"])
|
|
14
30
|
end
|
|
15
31
|
|
|
16
|
-
# Retrieve group metadata by
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
32
|
+
# Retrieve group metadata by id. Pass `include: "participants"` to embed
|
|
33
|
+
# the participant list.
|
|
34
|
+
def retrieve(group_id, include: nil)
|
|
35
|
+
params = include.nil? ? nil : { "include" => include }
|
|
36
|
+
env = client.request("GET", "/v1/groups/#{group_id}", params: params)
|
|
37
|
+
Types::Group.from_hash(env && env["data"])
|
|
20
38
|
end
|
|
21
39
|
|
|
22
|
-
# Rename the group and/or update admin-only settings.
|
|
40
|
+
# Rename the group and/or update admin-only settings. `settings` is a hash
|
|
41
|
+
# using the API's wire keys (announce, restrict, editInfoAdminsOnly,
|
|
42
|
+
# description).
|
|
23
43
|
def update(group_id, name: nil, settings: nil)
|
|
24
44
|
body = {}
|
|
25
45
|
body["name"] = name unless name.nil?
|
|
26
46
|
body["settings"] = settings unless settings.nil?
|
|
27
|
-
|
|
28
|
-
Types::Group.from_hash(data)
|
|
47
|
+
env = client.request("PATCH", "/v1/groups/#{group_id}", body: body)
|
|
48
|
+
Types::Group.from_hash(env && env["data"])
|
|
29
49
|
end
|
|
30
50
|
|
|
31
|
-
# Add
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
# Add members to the group by chat id (JID / +E.164) and/or a list of
|
|
52
|
+
# participants.
|
|
53
|
+
def add_members(group_id, chat_id: nil, participants: nil)
|
|
54
|
+
body = {}
|
|
55
|
+
body["chatId"] = chat_id unless chat_id.nil?
|
|
56
|
+
body["participants"] = participants unless participants.nil?
|
|
57
|
+
env = client.request("POST", "/v1/groups/#{group_id}/members", body: body)
|
|
58
|
+
Types::Group.from_hash(env && env["data"])
|
|
36
59
|
end
|
|
37
60
|
|
|
38
61
|
# Remove a participant from the group.
|
|
39
62
|
def remove_member(group_id, chat_id)
|
|
40
|
-
|
|
41
|
-
Types::Group.from_hash(data)
|
|
63
|
+
env = client.request("DELETE", "/v1/groups/#{group_id}/members/#{chat_id}")
|
|
64
|
+
Types::Group.from_hash(env && env["data"])
|
|
42
65
|
end
|
|
43
66
|
|
|
44
67
|
# Grant admin privileges to a group member.
|
|
45
68
|
def promote_admin(group_id, chat_id)
|
|
46
|
-
|
|
47
|
-
Types::Group.from_hash(data)
|
|
69
|
+
env = client.request("POST", "/v1/groups/#{group_id}/members/#{chat_id}/admin")
|
|
70
|
+
Types::Group.from_hash(env && env["data"])
|
|
48
71
|
end
|
|
49
72
|
|
|
50
73
|
# Revoke admin privileges from a group member.
|
|
51
74
|
def demote_admin(group_id, chat_id)
|
|
52
|
-
|
|
53
|
-
Types::Group.from_hash(data)
|
|
75
|
+
env = client.request("DELETE", "/v1/groups/#{group_id}/members/#{chat_id}/admin")
|
|
76
|
+
Types::Group.from_hash(env && env["data"])
|
|
54
77
|
end
|
|
55
78
|
|
|
56
|
-
# Replace the group picture. `file_data_url` is a base64 data URL
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
body
|
|
60
|
-
body["
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
# Replace the group picture. `file_data_url` is a base64 data URL, or pass
|
|
80
|
+
# a hosted `url`.
|
|
81
|
+
def set_picture(group_id, file_data_url: nil, url: nil, file_name: nil, file_mime_type: nil)
|
|
82
|
+
body = {}
|
|
83
|
+
body["fileDataUrl"] = file_data_url unless file_data_url.nil?
|
|
84
|
+
body["url"] = url unless url.nil?
|
|
85
|
+
body["fileName"] = file_name unless file_name.nil?
|
|
86
|
+
body["fileMimeType"] = file_mime_type unless file_mime_type.nil?
|
|
87
|
+
env = client.request("PUT", "/v1/groups/#{group_id}/picture", body: body)
|
|
88
|
+
Types::Group.from_hash(env && env["data"])
|
|
63
89
|
end
|
|
64
90
|
|
|
65
91
|
# Leave the group as the authenticated identity. Idempotent (204).
|
|
@@ -2,46 +2,125 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
4
|
require_relative "../types/messages"
|
|
5
|
-
require_relative "../types/
|
|
5
|
+
require_relative "../types/ok_result"
|
|
6
|
+
require_relative "../types/paginated"
|
|
6
7
|
|
|
7
8
|
module Blueticks
|
|
8
9
|
module Resources
|
|
9
10
|
class MessagesResource < BaseResource
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Types::Message.from_hash(data)
|
|
11
|
+
# Query messages from the WhatsApp store, newest first. Offset-paginated
|
|
12
|
+
# (PublicMessage rows). `message_types` is an Array of wire message types
|
|
13
|
+
# (e.g. `%w[chat image]`).
|
|
14
|
+
def list(chat_id: nil, search_token: nil, order: nil, since: nil, until_: nil,
|
|
15
|
+
message_types: nil, load_from_phone_if_needed: nil,
|
|
16
|
+
include_media_content: nil, skip: nil, limit: nil)
|
|
17
|
+
params = {}
|
|
18
|
+
params["chatId"] = chat_id unless chat_id.nil?
|
|
19
|
+
params["searchToken"] = search_token unless search_token.nil?
|
|
20
|
+
params["order"] = order unless order.nil?
|
|
21
|
+
params["since"] = since unless since.nil?
|
|
22
|
+
params["until"] = until_ unless until_.nil?
|
|
23
|
+
params["messageTypes"] = message_types.join(",") if message_types && !message_types.empty?
|
|
24
|
+
params["loadFromPhoneIfNeeded"] = load_from_phone_if_needed unless load_from_phone_if_needed.nil?
|
|
25
|
+
params["includeMediaContent"] = include_media_content unless include_media_content.nil?
|
|
26
|
+
params["skip"] = skip unless skip.nil?
|
|
27
|
+
params["limit"] = limit unless limit.nil?
|
|
28
|
+
env = client.request("GET", "/v1/messages", params: params.empty? ? nil : params)
|
|
29
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::PublicMessage)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
# Retrieve a single message by
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
# Retrieve a single store message by its serialized wire key. Pass
|
|
33
|
+
# `chat_id` to scope the lookup.
|
|
34
|
+
def retrieve(wa_message_key, chat_id: nil)
|
|
35
|
+
params = chat_id.nil? ? nil : { "chatId" => chat_id }
|
|
36
|
+
env = client.request("GET", "/v1/messages/#{wa_message_key}", params: params)
|
|
37
|
+
Types::PublicMessage.from_hash(env && env["data"])
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
#
|
|
39
|
-
def
|
|
40
|
+
# Get delivery acknowledgement for a single message.
|
|
41
|
+
def get_ack(wa_message_key, chat_id: nil)
|
|
42
|
+
params = chat_id.nil? ? nil : { "chatId" => chat_id }
|
|
43
|
+
env = client.request("GET", "/v1/messages/ack/#{wa_message_key}", params: params)
|
|
44
|
+
Types::MessageAck.from_hash(env && env["data"])
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Batch get delivery status for up to 200 sent messages. Offset-paginated
|
|
48
|
+
# (BatchAckEntry rows).
|
|
49
|
+
def batch_acks(message_keys:, chat_id: nil)
|
|
50
|
+
body = { "messageKeys" => message_keys }
|
|
51
|
+
body["chatId"] = chat_id unless chat_id.nil?
|
|
52
|
+
env = client.request("POST", "/v1/messages/acks", body: body)
|
|
53
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::BatchAckEntry)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Ask the engine to pull older history from the connected phone.
|
|
57
|
+
def load_older(chat_id)
|
|
58
|
+
env = client.request("POST", "/v1/messages/load_older/#{chat_id}")
|
|
59
|
+
Types::LoadOlderResult.from_hash(env && env["data"])
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Fetch media (URL and/or base64 bytes) for a message.
|
|
63
|
+
def get_media(wa_message_key, chat_id: nil, max_attempts: nil)
|
|
40
64
|
params = {}
|
|
41
|
-
params["
|
|
42
|
-
params["
|
|
43
|
-
|
|
44
|
-
|
|
65
|
+
params["chatId"] = chat_id unless chat_id.nil?
|
|
66
|
+
params["maxAttempts"] = max_attempts unless max_attempts.nil?
|
|
67
|
+
env = client.request("GET", "/v1/messages/media/#{wa_message_key}",
|
|
68
|
+
params: params.empty? ? nil : params)
|
|
69
|
+
Types::Media.from_hash(env && env["data"])
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Pin a message. Optional `duration` (seconds) sets the pin TTL.
|
|
73
|
+
def pin(wa_message_key, chat_id: nil, duration: nil)
|
|
74
|
+
params = chat_id.nil? ? nil : { "chatId" => chat_id }
|
|
75
|
+
body = {}
|
|
76
|
+
body["duration"] = duration unless duration.nil?
|
|
77
|
+
env = client.request("POST", "/v1/messages/pin/#{wa_message_key}", params: params, body: body)
|
|
78
|
+
Types::OkResult.from_hash(env && env["data"])
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Unpin a message.
|
|
82
|
+
def unpin(wa_message_key, chat_id: nil)
|
|
83
|
+
params = chat_id.nil? ? nil : { "chatId" => chat_id }
|
|
84
|
+
env = client.request("POST", "/v1/messages/unpin/#{wa_message_key}", params: params)
|
|
85
|
+
Types::OkResult.from_hash(env && env["data"])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# List the pinned messages in a chat. Offset-paginated (PinnedMessage rows).
|
|
89
|
+
def pinned(chat_id)
|
|
90
|
+
env = client.request("GET", "/v1/messages/pinned/#{chat_id}")
|
|
91
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::PinnedMessage)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# React to a message. Pass an empty `emoji` string to remove a reaction.
|
|
95
|
+
def react(wa_message_key, emoji:, chat_id: nil)
|
|
96
|
+
params = chat_id.nil? ? nil : { "chatId" => chat_id }
|
|
97
|
+
env = client.request("POST", "/v1/messages/reactions/#{wa_message_key}",
|
|
98
|
+
params: params, body: { "emoji" => emoji })
|
|
99
|
+
Types::OkResult.from_hash(env && env["data"])
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Send a message immediately to a chat (direct dispatch — no queue row is
|
|
103
|
+
# persisted for the wait; the response carries the WhatsApp wire key). The
|
|
104
|
+
# body is a discriminated union keyed on `type` (`text`, `media`, `poll`).
|
|
105
|
+
def create(chat_id, type:, text: nil, media_url: nil, media_base64: nil,
|
|
106
|
+
media_kind: nil, media_filename: nil, poll_question: nil,
|
|
107
|
+
poll_options: nil, poll_allow_multiple: nil, reply_to: nil,
|
|
108
|
+
secret: nil, with_typing: nil, typing_seconds: nil, idempotency_key: nil)
|
|
109
|
+
body = { "type" => type }
|
|
110
|
+
body["text"] = text unless text.nil?
|
|
111
|
+
body["mediaUrl"] = media_url unless media_url.nil?
|
|
112
|
+
body["mediaBase64"] = media_base64 unless media_base64.nil?
|
|
113
|
+
body["mediaKind"] = media_kind unless media_kind.nil?
|
|
114
|
+
body["mediaFilename"] = media_filename unless media_filename.nil?
|
|
115
|
+
body["pollQuestion"] = poll_question unless poll_question.nil?
|
|
116
|
+
body["pollOptions"] = poll_options unless poll_options.nil?
|
|
117
|
+
body["pollAllowMultiple"] = poll_allow_multiple unless poll_allow_multiple.nil?
|
|
118
|
+
body["replyTo"] = reply_to unless reply_to.nil?
|
|
119
|
+
body["secret"] = secret unless secret.nil?
|
|
120
|
+
body["withTyping"] = with_typing unless with_typing.nil?
|
|
121
|
+
body["typingSeconds"] = typing_seconds unless typing_seconds.nil?
|
|
122
|
+
env = client.request("POST", "/v1/messages/#{chat_id}", body: body, idempotency_key: idempotency_key)
|
|
123
|
+
Types::Message.from_hash(env && env["data"])
|
|
45
124
|
end
|
|
46
125
|
end
|
|
47
126
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../base_resource"
|
|
4
|
+
require_relative "../types/newsletter"
|
|
5
|
+
require_relative "../types/paginated"
|
|
6
|
+
|
|
7
|
+
module Blueticks
|
|
8
|
+
module Resources
|
|
9
|
+
class NewslettersResource < BaseResource
|
|
10
|
+
# List newsletters.
|
|
11
|
+
#
|
|
12
|
+
# List newsletters visible to the connected WhatsApp engine. Offset-paginated
|
|
13
|
+
# (NewsletterListItem rows). Requires `newsletters:read` scope.
|
|
14
|
+
def list(search_token: nil, include_archive: nil, skip: nil, limit: nil)
|
|
15
|
+
params = {}
|
|
16
|
+
params["searchToken"] = search_token unless search_token.nil?
|
|
17
|
+
params["includeArchive"] = include_archive unless include_archive.nil?
|
|
18
|
+
params["skip"] = skip unless skip.nil?
|
|
19
|
+
params["limit"] = limit unless limit.nil?
|
|
20
|
+
env = client.request("GET", "/v1/newsletters", params: params.empty? ? nil : params)
|
|
21
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::NewsletterListItem)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Create newsletter.
|
|
25
|
+
#
|
|
26
|
+
# Create a new WhatsApp newsletter (channel). Requires `messages:write` scope.
|
|
27
|
+
def create(name:, description: nil)
|
|
28
|
+
body = { "name" => name }
|
|
29
|
+
body["description"] = description unless description.nil?
|
|
30
|
+
env = client.request("POST", "/v1/newsletters", body: body)
|
|
31
|
+
Types::Newsletter.from_hash(env && env["data"])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Get newsletter.
|
|
35
|
+
#
|
|
36
|
+
# Retrieve a newsletter by its JID. Requires `newsletters:read` scope.
|
|
37
|
+
def retrieve(newsletter_id)
|
|
38
|
+
env = client.request("GET", "/v1/newsletters/#{newsletter_id}")
|
|
39
|
+
Types::Newsletter.from_hash(env && env["data"])
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -6,10 +6,13 @@ require_relative "../types/ping"
|
|
|
6
6
|
module Blueticks
|
|
7
7
|
module Resources
|
|
8
8
|
class PingResource < BaseResource
|
|
9
|
-
#
|
|
9
|
+
# Ping.
|
|
10
|
+
#
|
|
11
|
+
# Probe the API: returns `api: "ok"`, the account id, and the currently
|
|
12
|
+
# connected WhatsApp engines. Useful as a connection/liveness test.
|
|
10
13
|
def retrieve
|
|
11
|
-
|
|
12
|
-
Types::Ping.from_hash(data)
|
|
14
|
+
env = client.request("GET", "/v1/ping")
|
|
15
|
+
Types::Ping.from_hash(env && env["data"])
|
|
13
16
|
end
|
|
14
17
|
end
|
|
15
18
|
end
|
|
@@ -2,49 +2,93 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
4
|
require_relative "../types/scheduled_messages"
|
|
5
|
-
require_relative "../types/
|
|
5
|
+
require_relative "../types/deleted_resource"
|
|
6
|
+
require_relative "../types/paginated"
|
|
6
7
|
|
|
7
8
|
module Blueticks
|
|
8
9
|
module Resources
|
|
9
10
|
class ScheduledMessagesResource < BaseResource
|
|
10
|
-
#
|
|
11
|
+
# Send / schedule a message to a chat.
|
|
11
12
|
#
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
# Queue a message for delivery to `chat_id` (a WhatsApp JID or phone). The
|
|
14
|
+
# body is a discriminated union keyed on `type` (`text`, `media`, `poll`).
|
|
15
|
+
# Omit `send_at` to dispatch as soon as possible, or pass an ISO-8601
|
|
16
|
+
# timestamp to schedule it.
|
|
17
|
+
#
|
|
18
|
+
# - `type: "text"` — requires `text`.
|
|
19
|
+
# - `type: "media"` — requires `media_url` or `media_base64`; optional
|
|
20
|
+
# `media_kind`, `media_filename`.
|
|
21
|
+
# - `type: "poll"` — requires `poll_question` and `poll_options`; optional
|
|
22
|
+
# `poll_allow_multiple`.
|
|
23
|
+
def create(chat_id, type:, text: nil, media_url: nil, media_base64: nil,
|
|
24
|
+
media_kind: nil, media_filename: nil, poll_question: nil,
|
|
25
|
+
poll_options: nil, poll_allow_multiple: nil, reply_to: nil,
|
|
26
|
+
secret: nil, send_at: nil, idempotency_key: nil)
|
|
27
|
+
body = { "type" => type }
|
|
28
|
+
body["text"] = text unless text.nil?
|
|
29
|
+
body["mediaUrl"] = media_url unless media_url.nil?
|
|
30
|
+
body["mediaBase64"] = media_base64 unless media_base64.nil?
|
|
31
|
+
body["mediaKind"] = media_kind unless media_kind.nil?
|
|
32
|
+
body["mediaFilename"] = media_filename unless media_filename.nil?
|
|
33
|
+
body["pollQuestion"] = poll_question unless poll_question.nil?
|
|
34
|
+
body["pollOptions"] = poll_options unless poll_options.nil?
|
|
35
|
+
body["pollAllowMultiple"] = poll_allow_multiple unless poll_allow_multiple.nil?
|
|
36
|
+
body["replyTo"] = reply_to unless reply_to.nil?
|
|
37
|
+
body["secret"] = secret unless secret.nil?
|
|
38
|
+
body["sendAt"] = send_at unless send_at.nil?
|
|
39
|
+
env = client.request("POST", "/v1/scheduled-messages/#{chat_id}", body: body,
|
|
40
|
+
idempotency_key: idempotency_key)
|
|
41
|
+
Types::ScheduledMessage.from_hash(env && env["data"])
|
|
19
42
|
end
|
|
20
43
|
|
|
21
|
-
# Get scheduled message.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
data = client.request("GET", "/v1/scheduled-messages/#{id}")
|
|
26
|
-
Types::ScheduledMessage.from_hash(data)
|
|
44
|
+
# Get the current status of a queued/scheduled message by id.
|
|
45
|
+
def retrieve(message_id)
|
|
46
|
+
env = client.request("GET", "/v1/scheduled-messages/#{message_id}")
|
|
47
|
+
Types::ScheduledMessage.from_hash(env && env["data"])
|
|
27
48
|
end
|
|
28
49
|
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
def
|
|
50
|
+
# List messages in the user-messages queue (all sources), newest first.
|
|
51
|
+
# Offset-paginated. Optionally filter by `chat_id` and/or lifecycle
|
|
52
|
+
# `status`.
|
|
53
|
+
def list(chat_id: nil, search_token: nil, status: nil, order: nil, skip: nil, limit: nil)
|
|
54
|
+
params = {}
|
|
55
|
+
params["chatId"] = chat_id unless chat_id.nil?
|
|
56
|
+
params["searchToken"] = search_token unless search_token.nil?
|
|
57
|
+
params["status"] = status unless status.nil?
|
|
58
|
+
params["order"] = order unless order.nil?
|
|
59
|
+
params["skip"] = skip unless skip.nil?
|
|
60
|
+
params["limit"] = limit unless limit.nil?
|
|
61
|
+
env = client.request("GET", "/v1/scheduled-messages", params: params.empty? ? nil : params)
|
|
62
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::ScheduledMessage)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Edit a previously-queued message that has not dispatched yet. Pass any
|
|
66
|
+
# subset of the editable fields.
|
|
67
|
+
def update(message_id, type: nil, text: nil, media_url: nil, media_base64: nil,
|
|
68
|
+
media_kind: nil, media_filename: nil, poll_question: nil,
|
|
69
|
+
poll_options: nil, poll_allow_multiple: nil, reply_to: nil,
|
|
70
|
+
secret: nil, send_at: nil)
|
|
33
71
|
body = {}
|
|
72
|
+
body["type"] = type unless type.nil?
|
|
34
73
|
body["text"] = text unless text.nil?
|
|
35
|
-
body["
|
|
36
|
-
body["
|
|
37
|
-
body["
|
|
38
|
-
|
|
39
|
-
|
|
74
|
+
body["mediaUrl"] = media_url unless media_url.nil?
|
|
75
|
+
body["mediaBase64"] = media_base64 unless media_base64.nil?
|
|
76
|
+
body["mediaKind"] = media_kind unless media_kind.nil?
|
|
77
|
+
body["mediaFilename"] = media_filename unless media_filename.nil?
|
|
78
|
+
body["pollQuestion"] = poll_question unless poll_question.nil?
|
|
79
|
+
body["pollOptions"] = poll_options unless poll_options.nil?
|
|
80
|
+
body["pollAllowMultiple"] = poll_allow_multiple unless poll_allow_multiple.nil?
|
|
81
|
+
body["replyTo"] = reply_to unless reply_to.nil?
|
|
82
|
+
body["secret"] = secret unless secret.nil?
|
|
83
|
+
body["sendAt"] = send_at unless send_at.nil?
|
|
84
|
+
env = client.request("PATCH", "/v1/scheduled-messages/#{message_id}", body: body)
|
|
85
|
+
Types::ScheduledMessage.from_hash(env && env["data"])
|
|
40
86
|
end
|
|
41
87
|
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
data = client.request("DELETE", "/v1/scheduled-messages/#{id}")
|
|
47
|
-
Types::ScheduledMessage.from_hash(data)
|
|
88
|
+
# Delete (cancel) a queued/scheduled message by id.
|
|
89
|
+
def delete(message_id)
|
|
90
|
+
env = client.request("DELETE", "/v1/scheduled-messages/#{message_id}")
|
|
91
|
+
Types::DeletedResource.from_hash(env && env["data"])
|
|
48
92
|
end
|
|
49
93
|
end
|
|
50
94
|
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../base_resource"
|
|
4
|
+
require_relative "../types/suno"
|
|
5
|
+
|
|
6
|
+
module Blueticks
|
|
7
|
+
module Resources
|
|
8
|
+
class SunoResource < BaseResource
|
|
9
|
+
# Get the Suno credit / plan usage for the workspace.
|
|
10
|
+
def account
|
|
11
|
+
env = client.request("GET", "/v1/suno/account")
|
|
12
|
+
Types::SunoAccount.from_hash(env && env["data"])
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Submit a song generation job. Requires `lyrics` and `style`; the many
|
|
16
|
+
# optional knobs mirror the Suno request (vocal_gender, weirdness,
|
|
17
|
+
# style_influence, audio_influence, instrumental, model, title, upload_id,
|
|
18
|
+
# captcha_token, negative_style).
|
|
19
|
+
def create_song(lyrics:, style:, negative_style: nil, vocal_gender: nil,
|
|
20
|
+
weirdness: nil, style_influence: nil, audio_influence: nil,
|
|
21
|
+
instrumental: nil, model: nil, title: nil, upload_id: nil,
|
|
22
|
+
captcha_token: nil)
|
|
23
|
+
body = { "lyrics" => lyrics, "style" => style }
|
|
24
|
+
body["negativeStyle"] = negative_style unless negative_style.nil?
|
|
25
|
+
body["vocalGender"] = vocal_gender unless vocal_gender.nil?
|
|
26
|
+
body["weirdness"] = weirdness unless weirdness.nil?
|
|
27
|
+
body["styleInfluence"] = style_influence unless style_influence.nil?
|
|
28
|
+
body["audioInfluence"] = audio_influence unless audio_influence.nil?
|
|
29
|
+
body["instrumental"] = instrumental unless instrumental.nil?
|
|
30
|
+
body["model"] = model unless model.nil?
|
|
31
|
+
body["title"] = title unless title.nil?
|
|
32
|
+
body["uploadId"] = upload_id unless upload_id.nil?
|
|
33
|
+
body["captchaToken"] = captcha_token unless captcha_token.nil?
|
|
34
|
+
env = client.request("POST", "/v1/suno/songs", body: body)
|
|
35
|
+
Types::GenerateSongResult.from_hash(env && env["data"])
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Get a generated song (clip) by id.
|
|
39
|
+
def get_song(song_id)
|
|
40
|
+
env = client.request("GET", "/v1/suno/songs/#{song_id}")
|
|
41
|
+
Types::SongClip.from_hash(env && env["data"])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Register a reference-audio upload (by URL or base64) for use as an
|
|
45
|
+
# influence on a subsequent song generation.
|
|
46
|
+
def create_upload(audio_url: nil, audio_base64: nil, file_name: nil)
|
|
47
|
+
body = {}
|
|
48
|
+
body["audioUrl"] = audio_url unless audio_url.nil?
|
|
49
|
+
body["audioBase64"] = audio_base64 unless audio_base64.nil?
|
|
50
|
+
body["fileName"] = file_name unless file_name.nil?
|
|
51
|
+
env = client.request("POST", "/v1/suno/uploads", body: body)
|
|
52
|
+
Types::CreateUploadResult.from_hash(env && env["data"])
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
|
-
require_relative "../types/utils"
|
|
5
4
|
|
|
6
5
|
module Blueticks
|
|
7
6
|
module Resources
|
|
7
|
+
# UtilsResource had methods for /v1/utils/* which are not in the current spec.
|
|
8
|
+
# The accessor is kept for backward compatibility with test_client.rb.
|
|
9
|
+
# No public methods are exposed.
|
|
8
10
|
class UtilsResource < BaseResource
|
|
9
|
-
# Validate a phone number or chat-id; returns the engine's canonical form.
|
|
10
|
-
def validate_phone(phone_or_chat_id:)
|
|
11
|
-
data = client.request("POST", "/v1/utils/validate_phone",
|
|
12
|
-
body: { "phone_or_chat_id" => phone_or_chat_id })
|
|
13
|
-
Types::PhoneValidation.from_hash(data)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Fetch OpenGraph-style metadata for a URL (uses the engine's renderer).
|
|
17
|
-
def link_preview(url:)
|
|
18
|
-
data = client.request("GET", "/v1/utils/link_preview", params: { "url" => url })
|
|
19
|
-
Types::LinkPreview.from_hash(data)
|
|
20
|
-
end
|
|
21
11
|
end
|
|
22
12
|
end
|
|
23
13
|
end
|
|
@@ -1,51 +1,52 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
|
+
require_relative "../types/deleted_resource"
|
|
4
5
|
require_relative "../types/webhooks"
|
|
5
|
-
require_relative "../types/
|
|
6
|
+
require_relative "../types/paginated"
|
|
6
7
|
|
|
7
8
|
module Blueticks
|
|
8
9
|
module Resources
|
|
9
10
|
class WebhooksResource < BaseResource
|
|
11
|
+
# Create a webhook subscription.
|
|
10
12
|
def create(url:, events:, description: nil)
|
|
11
13
|
body = { "url" => url, "events" => events }
|
|
12
14
|
body["description"] = description unless description.nil?
|
|
13
|
-
|
|
14
|
-
Types::
|
|
15
|
+
env = client.request("POST", "/v1/webhooks", body: body)
|
|
16
|
+
Types::Webhook.from_hash(env && env["data"])
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
# List webhooks, newest first.
|
|
18
|
-
def list(
|
|
19
|
+
# List webhooks, newest first. Offset-paginated.
|
|
20
|
+
def list(order: nil, skip: nil, limit: nil)
|
|
19
21
|
params = {}
|
|
22
|
+
params["order"] = order unless order.nil?
|
|
23
|
+
params["skip"] = skip unless skip.nil?
|
|
20
24
|
params["limit"] = limit unless limit.nil?
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Types::Page.from_hash(data, item_type: Types::Webhook)
|
|
25
|
+
env = client.request("GET", "/v1/webhooks", params: params.empty? ? nil : params)
|
|
26
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::Webhook)
|
|
24
27
|
end
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
# Retrieve a webhook by id.
|
|
30
|
+
def retrieve(webhook_id)
|
|
31
|
+
env = client.request("GET", "/v1/webhooks/#{webhook_id}")
|
|
32
|
+
Types::Webhook.from_hash(env && env["data"])
|
|
29
33
|
end
|
|
30
34
|
|
|
35
|
+
# Update a webhook's url, events, description and/or status.
|
|
31
36
|
def update(webhook_id, url: nil, events: nil, description: nil, status: nil)
|
|
32
37
|
body = {}
|
|
33
38
|
body["url"] = url unless url.nil?
|
|
34
39
|
body["events"] = events unless events.nil?
|
|
35
40
|
body["description"] = description unless description.nil?
|
|
36
41
|
body["status"] = status unless status.nil?
|
|
37
|
-
|
|
38
|
-
Types::Webhook.from_hash(data)
|
|
42
|
+
env = client.request("PATCH", "/v1/webhooks/#{webhook_id}", body: body)
|
|
43
|
+
Types::Webhook.from_hash(env && env["data"])
|
|
39
44
|
end
|
|
40
45
|
|
|
46
|
+
# Delete a webhook.
|
|
41
47
|
def delete(webhook_id)
|
|
42
|
-
client.request("DELETE", "/v1/webhooks/#{webhook_id}")
|
|
43
|
-
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def rotate_secret(webhook_id)
|
|
47
|
-
data = client.request("POST", "/v1/webhooks/#{webhook_id}/rotate-secret")
|
|
48
|
-
Types::WebhookCreateResult.from_hash(data)
|
|
48
|
+
env = client.request("DELETE", "/v1/webhooks/#{webhook_id}")
|
|
49
|
+
Types::DeletedResource.from_hash(env && env["data"])
|
|
49
50
|
end
|
|
50
51
|
end
|
|
51
52
|
end
|
|
@@ -8,8 +8,9 @@ module Blueticks
|
|
|
8
8
|
class Account < Base
|
|
9
9
|
field :id, :string
|
|
10
10
|
field :name, :string
|
|
11
|
+
field :user_email, :string, nullable: true, wire_name: "userEmail"
|
|
11
12
|
field :timezone, :string, nullable: true
|
|
12
|
-
field :created_at, :string
|
|
13
|
+
field :created_at, :string, wire_name: "createdAt"
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
end
|