blueticks 1.1.2 → 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 +30 -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 -32
- data/lib/blueticks/resources/suno.rb +56 -0
- data/lib/blueticks/resources/utils.rb +3 -13
- data/lib/blueticks/resources/webhooks.rb +20 -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 -78
- data/lib/blueticks/types/contacts.rb +6 -7
- 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 +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 62b2a3ae7e59ee684634e2e2e26883fa47db18da62aa74eda711efd088d4e868
|
|
4
|
+
data.tar.gz: 392f498378faa47fa4be6f73fbefad15a5642ab16718ec2fdd9787a8aa5951a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e3a873bb77d76820cf1946483f11eabf2c53169c3930f1578fbbaa86679193e6428071aed414d4d9c41f5f99beb3dfd7bac411e9db84ebcad3e66b364e5f9def
|
|
7
|
+
data.tar.gz: 681cf759086355b74cdba8fec69cf515b62705b7a8a0039916c25a267dc34928d2f24c2a62dc948e3c04ea909c45f618cb0803677cc3efe0a56a2568447576d4
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,47 @@ All notable changes to the Blueticks Ruby SDK are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this
|
|
5
5
|
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## 1.2.0 — 2026-05-22
|
|
8
|
+
|
|
9
|
+
OpenAPI parity pass. The SDK now matches `backend/openapi.json`
|
|
10
|
+
operation-for-operation; an engineless drift check
|
|
11
|
+
(`.github/workflows/sdk-spec-drift.yml`) gates future regressions. The
|
|
12
|
+
`/v1/*` surface is pre-release — none of these changes affect production
|
|
13
|
+
callers yet.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- `messages.send` now takes the discriminated body shape matching the
|
|
18
|
+
backend's strict `anyOf` (BE#50):
|
|
19
|
+
```ruby
|
|
20
|
+
client.messages.send(to: '+1...', type: 'text', text: 'hi')
|
|
21
|
+
client.messages.send(to: '+1...', type: 'media', media: { url: '...', kind: 'image' })
|
|
22
|
+
client.messages.send(to: '+1...', type: 'poll', poll: { question: '...', options: [...] })
|
|
23
|
+
```
|
|
24
|
+
- Single-item GETs now use `.retrieve(id)` instead of `.get(id)` where the
|
|
25
|
+
spec uses GET-by-id. Also `engines.status` → `engines.retrieve`.
|
|
26
|
+
- `newsletters.create` returns the typed `Blueticks::Types::Newsletter` (8
|
|
27
|
+
fields) instead of a raw Hash.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- `newsletters.list(limit:, cursor:)` — `GET /v1/newsletters` (cursor-paginated → `Page<Newsletter>`)
|
|
32
|
+
- `newsletters.retrieve(id)` — `GET /v1/newsletters/{id}`
|
|
33
|
+
- `ping.retrieve` — typed `Ping` (`account_id`, `key_prefix`, `scopes`). The
|
|
34
|
+
`ping` resource had been deleted in a prior interim regen; restored here.
|
|
35
|
+
- `Message` now exposes `key`, `type`, `media_kind`, `poll_question`, `link_preview`
|
|
36
|
+
|
|
37
|
+
### Removed
|
|
38
|
+
|
|
39
|
+
- `engines.me`, `engines.logout`, `engines.reload`
|
|
40
|
+
- `contacts.get_profile_picture`
|
|
41
|
+
- `utils.validate_phone`, `utils.link_preview` (the `utils` resource was emptied)
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- `groups.list` was documented at `dev.blueticks.co` but absent from the
|
|
46
|
+
SDK for ~9 days — now present.
|
|
47
|
+
|
|
7
48
|
## 1.0.0 — 2026-04-30
|
|
8
49
|
|
|
9
50
|
Initial release.
|
data/lib/blueticks/client.rb
CHANGED
|
@@ -2,13 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "errors"
|
|
4
4
|
require_relative "transport"
|
|
5
|
+
require_relative "resources/account"
|
|
6
|
+
require_relative "resources/audiences"
|
|
7
|
+
require_relative "resources/campaigns"
|
|
8
|
+
require_relative "resources/chats"
|
|
9
|
+
require_relative "resources/contacts"
|
|
10
|
+
require_relative "resources/engines"
|
|
11
|
+
require_relative "resources/groups"
|
|
12
|
+
require_relative "resources/messages"
|
|
13
|
+
require_relative "resources/newsletters"
|
|
14
|
+
require_relative "resources/ping"
|
|
5
15
|
require_relative "resources/scheduled_messages"
|
|
16
|
+
require_relative "resources/suno"
|
|
17
|
+
require_relative "resources/utils"
|
|
18
|
+
require_relative "resources/webhooks"
|
|
6
19
|
|
|
7
20
|
module Blueticks
|
|
8
21
|
# Top-level entry point. Construct one and access resources via accessor methods:
|
|
9
22
|
#
|
|
10
23
|
# client = Blueticks::Client.new(api_key: "bt_live_...")
|
|
11
|
-
# client.
|
|
24
|
+
# client.scheduled_messages.create(type: "text", to: "12025550100", text: "Hello!")
|
|
12
25
|
#
|
|
13
26
|
# Configuration order of precedence:
|
|
14
27
|
# 1. Explicit keyword args.
|
|
@@ -47,10 +60,6 @@ module Blueticks
|
|
|
47
60
|
@ping ||= Resources::PingResource.new(self)
|
|
48
61
|
end
|
|
49
62
|
|
|
50
|
-
def messages
|
|
51
|
-
@messages ||= Resources::MessagesResource.new(self)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
63
|
def scheduled_messages
|
|
55
64
|
@scheduled_messages ||= Resources::ScheduledMessagesResource.new(self)
|
|
56
65
|
end
|
|
@@ -83,6 +92,19 @@ module Blueticks
|
|
|
83
92
|
@contacts ||= Resources::ContactsResource.new(self)
|
|
84
93
|
end
|
|
85
94
|
|
|
95
|
+
def newsletters
|
|
96
|
+
@newsletters ||= Resources::NewslettersResource.new(self)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def messages
|
|
100
|
+
@messages ||= Resources::MessagesResource.new(self)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def suno
|
|
104
|
+
@suno ||= Resources::SunoResource.new(self)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Kept for backward compatibility. No spec-backed operations exposed.
|
|
86
108
|
def utils
|
|
87
109
|
@utils ||= Resources::UtilsResource.new(self)
|
|
88
110
|
end
|
|
@@ -10,8 +10,8 @@ module Blueticks
|
|
|
10
10
|
#
|
|
11
11
|
# Returns the account associated with the API key used for this request.
|
|
12
12
|
def retrieve
|
|
13
|
-
|
|
14
|
-
Types::Account.from_hash(data)
|
|
13
|
+
env = client.request("GET", "/v1/account")
|
|
14
|
+
Types::Account.from_hash(env && env["data"])
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -3,67 +3,75 @@
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
4
|
require_relative "../types/audiences"
|
|
5
5
|
require_relative "../types/deleted_resource"
|
|
6
|
-
require_relative "../types/
|
|
6
|
+
require_relative "../types/paginated"
|
|
7
7
|
|
|
8
8
|
module Blueticks
|
|
9
9
|
module Resources
|
|
10
10
|
class AudiencesResource < BaseResource
|
|
11
|
+
# Create an audience, optionally seeding it with contacts.
|
|
12
|
+
# `contacts` is an Array of `{ "to" => ..., "variables" => {...} }` hashes.
|
|
11
13
|
def create(name:, contacts: nil)
|
|
12
14
|
body = { "name" => name }
|
|
13
15
|
body["contacts"] = contacts unless contacts.nil?
|
|
14
|
-
|
|
15
|
-
Types::Audience.from_hash(data)
|
|
16
|
+
env = client.request("POST", "/v1/audiences", body: body)
|
|
17
|
+
Types::Audience.from_hash(env && env["data"])
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
# List audiences, newest first.
|
|
19
|
-
def list(
|
|
20
|
+
# List audiences, newest first. Offset-paginated.
|
|
21
|
+
def list(order: nil, skip: nil, limit: nil)
|
|
20
22
|
params = {}
|
|
23
|
+
params["order"] = order unless order.nil?
|
|
24
|
+
params["skip"] = skip unless skip.nil?
|
|
21
25
|
params["limit"] = limit unless limit.nil?
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Types::Page.from_hash(data, item_type: Types::Audience)
|
|
26
|
+
env = client.request("GET", "/v1/audiences", params: params.empty? ? nil : params)
|
|
27
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::Audience)
|
|
25
28
|
end
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Types::Audience.from_hash(data)
|
|
30
|
+
# Retrieve an audience by id.
|
|
31
|
+
def retrieve(audience_id)
|
|
32
|
+
env = client.request("GET", "/v1/audiences/#{audience_id}")
|
|
33
|
+
Types::Audience.from_hash(env && env["data"])
|
|
31
34
|
end
|
|
32
35
|
|
|
36
|
+
# Rename an audience.
|
|
33
37
|
def update(audience_id, name:)
|
|
34
|
-
|
|
35
|
-
Types::Audience.from_hash(data)
|
|
38
|
+
env = client.request("PATCH", "/v1/audiences/#{audience_id}", body: { "name" => name })
|
|
39
|
+
Types::Audience.from_hash(env && env["data"])
|
|
36
40
|
end
|
|
37
41
|
|
|
42
|
+
# Delete an audience.
|
|
38
43
|
def delete(audience_id)
|
|
39
|
-
|
|
40
|
-
Types::DeletedResource.from_hash(data)
|
|
44
|
+
env = client.request("DELETE", "/v1/audiences/#{audience_id}")
|
|
45
|
+
Types::DeletedResource.from_hash(env && env["data"])
|
|
41
46
|
end
|
|
42
47
|
|
|
48
|
+
# Append contacts to an audience.
|
|
43
49
|
def append_contacts(audience_id, contacts:)
|
|
44
|
-
|
|
50
|
+
env = client.request(
|
|
45
51
|
"POST",
|
|
46
52
|
"/v1/audiences/#{audience_id}/contacts",
|
|
47
53
|
body: { "contacts" => contacts }
|
|
48
54
|
)
|
|
49
|
-
Types::AppendContactsResult.from_hash(data)
|
|
55
|
+
Types::AppendContactsResult.from_hash(env && env["data"])
|
|
50
56
|
end
|
|
51
57
|
|
|
58
|
+
# Update a single contact's recipient and/or merge-field variables.
|
|
52
59
|
def update_contact(audience_id, contact_id, to: nil, variables: nil)
|
|
53
60
|
body = {}
|
|
54
61
|
body["to"] = to unless to.nil?
|
|
55
62
|
body["variables"] = variables unless variables.nil?
|
|
56
|
-
|
|
63
|
+
env = client.request(
|
|
57
64
|
"PATCH",
|
|
58
65
|
"/v1/audiences/#{audience_id}/contacts/#{contact_id}",
|
|
59
66
|
body: body
|
|
60
67
|
)
|
|
61
|
-
Types::
|
|
68
|
+
Types::AudienceContact.from_hash(env && env["data"])
|
|
62
69
|
end
|
|
63
70
|
|
|
71
|
+
# Remove a contact from an audience.
|
|
64
72
|
def delete_contact(audience_id, contact_id)
|
|
65
|
-
client.request("DELETE", "/v1/audiences/#{audience_id}/contacts/#{contact_id}")
|
|
66
|
-
|
|
73
|
+
env = client.request("DELETE", "/v1/audiences/#{audience_id}/contacts/#{contact_id}")
|
|
74
|
+
Types::ContactRemoval.from_hash(env && env["data"])
|
|
67
75
|
end
|
|
68
76
|
end
|
|
69
77
|
end
|
|
@@ -2,50 +2,55 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
4
|
require_relative "../types/campaigns"
|
|
5
|
-
require_relative "../types/
|
|
5
|
+
require_relative "../types/paginated"
|
|
6
6
|
|
|
7
7
|
module Blueticks
|
|
8
8
|
module Resources
|
|
9
9
|
class CampaignsResource < BaseResource
|
|
10
|
+
# Create a campaign against an audience.
|
|
10
11
|
def create(name:, audience_id:, text: nil, media_url: nil, media_caption: nil,
|
|
11
|
-
|
|
12
|
-
body = { "name" => name, "
|
|
12
|
+
on_missing_variable: nil)
|
|
13
|
+
body = { "name" => name, "audienceId" => audience_id }
|
|
13
14
|
body["text"] = text unless text.nil?
|
|
14
|
-
body["
|
|
15
|
-
body["
|
|
16
|
-
body["
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Types::Campaign.from_hash(data)
|
|
15
|
+
body["mediaUrl"] = media_url unless media_url.nil?
|
|
16
|
+
body["mediaCaption"] = media_caption unless media_caption.nil?
|
|
17
|
+
body["onMissingVariable"] = on_missing_variable unless on_missing_variable.nil?
|
|
18
|
+
env = client.request("POST", "/v1/campaigns", body: body)
|
|
19
|
+
Types::Campaign.from_hash(env && env["data"])
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
# List campaigns, newest first.
|
|
23
|
-
def list(
|
|
22
|
+
# List campaigns, newest first. Offset-paginated.
|
|
23
|
+
def list(order: nil, skip: nil, limit: nil)
|
|
24
24
|
params = {}
|
|
25
|
+
params["order"] = order unless order.nil?
|
|
26
|
+
params["skip"] = skip unless skip.nil?
|
|
25
27
|
params["limit"] = limit unless limit.nil?
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Types::Page.from_hash(data, item_type: Types::Campaign)
|
|
28
|
+
env = client.request("GET", "/v1/campaigns", params: params.empty? ? nil : params)
|
|
29
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::Campaign)
|
|
29
30
|
end
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
# Retrieve a campaign by id.
|
|
33
|
+
def retrieve(campaign_id)
|
|
34
|
+
env = client.request("GET", "/v1/campaigns/#{campaign_id}")
|
|
35
|
+
Types::Campaign.from_hash(env && env["data"])
|
|
34
36
|
end
|
|
35
37
|
|
|
38
|
+
# Pause a running campaign.
|
|
36
39
|
def pause(campaign_id)
|
|
37
|
-
|
|
38
|
-
Types::Campaign.from_hash(data)
|
|
40
|
+
env = client.request("POST", "/v1/campaigns/#{campaign_id}/pause")
|
|
41
|
+
Types::Campaign.from_hash(env && env["data"])
|
|
39
42
|
end
|
|
40
43
|
|
|
44
|
+
# Resume a paused campaign.
|
|
41
45
|
def resume(campaign_id)
|
|
42
|
-
|
|
43
|
-
Types::Campaign.from_hash(data)
|
|
46
|
+
env = client.request("POST", "/v1/campaigns/#{campaign_id}/resume")
|
|
47
|
+
Types::Campaign.from_hash(env && env["data"])
|
|
44
48
|
end
|
|
45
49
|
|
|
50
|
+
# Cancel a campaign.
|
|
46
51
|
def cancel(campaign_id)
|
|
47
|
-
|
|
48
|
-
Types::Campaign.from_hash(data)
|
|
52
|
+
env = client.request("POST", "/v1/campaigns/#{campaign_id}/cancel")
|
|
53
|
+
Types::Campaign.from_hash(env && env["data"])
|
|
49
54
|
end
|
|
50
55
|
end
|
|
51
56
|
end
|
|
@@ -2,111 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
4
|
require_relative "../types/chats"
|
|
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 ChatsResource < BaseResource
|
|
10
|
-
# List/search chats, newest first.
|
|
11
|
-
def list(
|
|
11
|
+
# List/search chats, newest first. Offset-paginated.
|
|
12
|
+
def list(search_token: nil, filter: nil, include_last_message: nil,
|
|
13
|
+
include_extended_info: nil, include_without_name: nil,
|
|
14
|
+
include_archive: nil, skip: nil, limit: nil)
|
|
12
15
|
params = {}
|
|
13
|
-
params["
|
|
16
|
+
params["searchToken"] = search_token unless search_token.nil?
|
|
17
|
+
params["filter"] = filter unless filter.nil?
|
|
18
|
+
params["includeLastMessage"] = include_last_message unless include_last_message.nil?
|
|
19
|
+
params["includeExtendedInfo"] = include_extended_info unless include_extended_info.nil?
|
|
20
|
+
params["includeWithoutName"] = include_without_name unless include_without_name.nil?
|
|
21
|
+
params["includeArchive"] = include_archive unless include_archive.nil?
|
|
22
|
+
params["skip"] = skip unless skip.nil?
|
|
14
23
|
params["limit"] = limit unless limit.nil?
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
Types::Page.from_hash(data, item_type: Types::Chat)
|
|
24
|
+
env = client.request("GET", "/v1/chats", params: params.empty? ? nil : params)
|
|
25
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::Chat)
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
# Retrieve a chat by its JID.
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
Types::Chat.from_hash(data)
|
|
29
|
+
def retrieve(chat_id)
|
|
30
|
+
env = client.request("GET", "/v1/chats/#{chat_id}")
|
|
31
|
+
Types::Chat.from_hash(env && env["data"])
|
|
24
32
|
end
|
|
25
33
|
|
|
26
|
-
# List participants in a group chat.
|
|
27
|
-
def list_participants(chat_id,
|
|
34
|
+
# List participants in a group/community chat. Offset-paginated.
|
|
35
|
+
def list_participants(chat_id, search_token: nil, skip: nil, limit: nil)
|
|
28
36
|
params = {}
|
|
37
|
+
params["searchToken"] = search_token unless search_token.nil?
|
|
38
|
+
params["skip"] = skip unless skip.nil?
|
|
29
39
|
params["limit"] = limit unless limit.nil?
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Types::Page.from_hash(data, item_type: Types::Participant)
|
|
40
|
+
env = client.request("GET", "/v1/chats/#{chat_id}/participants",
|
|
41
|
+
params: params.empty? ? nil : params)
|
|
42
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::Participant)
|
|
34
43
|
end
|
|
35
44
|
|
|
36
|
-
#
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
Types::
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Open a chat on the engine (useful for UI-assisted workflows).
|
|
43
|
-
def open(chat_id)
|
|
44
|
-
data = client.request("POST", "/v1/chats/#{chat_id}/open")
|
|
45
|
-
Types::ChatRef.from_hash(data)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# List messages in a chat. `mode` is "latest" or "history".
|
|
49
|
-
def list_messages(chat_id, mode: "latest", query: nil, since: nil, until_: nil,
|
|
50
|
-
message_types: nil, limit: nil, cursor: nil)
|
|
51
|
-
params = { "mode" => mode }
|
|
52
|
-
params["query"] = query unless query.nil?
|
|
53
|
-
params["since"] = since unless since.nil?
|
|
54
|
-
params["until"] = until_ unless until_.nil?
|
|
55
|
-
params["message_types"] = message_types.join(",") if message_types && !message_types.empty?
|
|
56
|
-
params["limit"] = limit unless limit.nil?
|
|
57
|
-
params["cursor"] = cursor unless cursor.nil?
|
|
58
|
-
data = client.request("GET", "/v1/chats/#{chat_id}/messages", params: params)
|
|
59
|
-
Types::Page.from_hash(data, item_type: Types::ChatMessage)
|
|
45
|
+
# Archive a chat.
|
|
46
|
+
def archive(chat_id)
|
|
47
|
+
env = client.request("POST", "/v1/chats/#{chat_id}/archive")
|
|
48
|
+
Types::OkResult.from_hash(env && env["data"])
|
|
60
49
|
end
|
|
61
50
|
|
|
62
|
-
#
|
|
63
|
-
def
|
|
64
|
-
|
|
65
|
-
Types::
|
|
51
|
+
# Unarchive a chat.
|
|
52
|
+
def unarchive(chat_id)
|
|
53
|
+
env = client.request("POST", "/v1/chats/#{chat_id}/unarchive")
|
|
54
|
+
Types::OkResult.from_hash(env && env["data"])
|
|
66
55
|
end
|
|
67
56
|
|
|
68
|
-
#
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
Types::
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# React to a message. Pass an empty `emoji` string to remove a reaction.
|
|
75
|
-
def react(chat_id, key, emoji:)
|
|
76
|
-
data = client.request(
|
|
77
|
-
"POST",
|
|
78
|
-
"/v1/chats/#{chat_id}/messages/#{key}/reactions",
|
|
79
|
-
body: { "emoji" => emoji }
|
|
80
|
-
)
|
|
81
|
-
Types::OkResponse.from_hash(data)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Ask the engine to pull older history from the connected phone.
|
|
85
|
-
def load_older_messages(chat_id)
|
|
86
|
-
data = client.request("POST", "/v1/chats/#{chat_id}/messages/load_older")
|
|
87
|
-
Types::LoadOlderMessagesResponse.from_hash(data)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Get a hosted URL for the message media without inlining bytes.
|
|
91
|
-
def get_media_url(chat_id, key)
|
|
92
|
-
data = client.request("GET", "/v1/chats/#{chat_id}/messages/#{key}/media_url")
|
|
93
|
-
Types::MediaUrlResponse.from_hash(data)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Fetch full media bytes (base64) for a message.
|
|
97
|
-
def get_media(chat_id, key)
|
|
98
|
-
data = client.request("GET", "/v1/chats/#{chat_id}/messages/#{key}/media")
|
|
99
|
-
Types::ChatMedia.from_hash(data)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Batch get delivery status for up to 200 sent messages.
|
|
103
|
-
def batch_message_acks(message_keys:)
|
|
104
|
-
data = client.request(
|
|
105
|
-
"POST",
|
|
106
|
-
"/v1/chats/message_acks",
|
|
107
|
-
body: { "message_keys" => message_keys }
|
|
108
|
-
)
|
|
109
|
-
Types::BatchMessageAcksResponse.from_hash(data)
|
|
57
|
+
# Mark a chat as read (sends read receipts if enabled).
|
|
58
|
+
def mark_read(chat_id)
|
|
59
|
+
env = client.request("POST", "/v1/chats/#{chat_id}/mark_read")
|
|
60
|
+
Types::OkResult.from_hash(env && env["data"])
|
|
110
61
|
end
|
|
111
62
|
end
|
|
112
63
|
end
|
|
@@ -2,25 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
4
|
require_relative "../types/contacts"
|
|
5
|
-
require_relative "../types/
|
|
5
|
+
require_relative "../types/groups"
|
|
6
|
+
require_relative "../types/paginated"
|
|
6
7
|
|
|
7
8
|
module Blueticks
|
|
8
9
|
module Resources
|
|
9
10
|
class ContactsResource < BaseResource
|
|
10
|
-
#
|
|
11
|
-
|
|
11
|
+
# List contacts.
|
|
12
|
+
#
|
|
13
|
+
# List WhatsApp contacts known to the connected engine. Offset-paginated.
|
|
14
|
+
def list(search_token: nil, include_archive: nil, skip: nil, limit: nil)
|
|
12
15
|
params = {}
|
|
13
|
-
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?
|
|
14
19
|
params["limit"] = limit unless limit.nil?
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
Types::Page.from_hash(data, item_type: Types::WhatsAppContact)
|
|
20
|
+
env = client.request("GET", "/v1/contacts", params: params.empty? ? nil : params)
|
|
21
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::WhatsAppContact)
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
# List groups in common.
|
|
25
|
+
#
|
|
26
|
+
# List the groups the authenticated user shares with the given contact.
|
|
27
|
+
# Offset-paginated (GroupListItem rows).
|
|
28
|
+
def common_groups(contact_id)
|
|
29
|
+
env = client.request("GET", "/v1/contacts/#{contact_id}/common_groups")
|
|
30
|
+
Types::PaginatedPage.from_hash(env, item_type: Types::GroupListItem)
|
|
24
31
|
end
|
|
25
32
|
end
|
|
26
33
|
end
|
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "../base_resource"
|
|
4
|
+
require_relative "../errors"
|
|
4
5
|
require_relative "../types/engines"
|
|
5
6
|
|
|
6
7
|
module Blueticks
|
|
7
8
|
module Resources
|
|
8
9
|
class EnginesResource < BaseResource
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Force the engine to log out of WhatsApp Web.
|
|
22
|
-
def logout
|
|
23
|
-
client.request("POST", "/v1/engines/logout")
|
|
24
|
-
end
|
|
10
|
+
# List engines.
|
|
11
|
+
#
|
|
12
|
+
# List the WhatsApp engines connected to the workspace. Returns an Array of
|
|
13
|
+
# Engine (empty when no engine is paired) — this endpoint is not paginated.
|
|
14
|
+
def list
|
|
15
|
+
env = client.request("GET", "/v1/engines")
|
|
16
|
+
data = env.is_a?(Hash) ? env["data"] : nil
|
|
17
|
+
unless data.is_a?(Array)
|
|
18
|
+
raise Errors::ValidationError.new(message: "Expected array `data` in engines.list response")
|
|
19
|
+
end
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
def reload
|
|
28
|
-
client.request("POST", "/v1/engines/reload")
|
|
21
|
+
data.map { |item| Types::Engine.from_hash(item) }
|
|
29
22
|
end
|
|
30
23
|
end
|
|
31
24
|
end
|