warb 1.0.0 → 1.0.1

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -5
  3. data/README.md +32 -9
  4. data/Rakefile +3 -3
  5. data/docs/README.md +4 -1
  6. data/docs/components/README.md +4 -1
  7. data/docs/components/button.md +62 -0
  8. data/docs/components/copy_code_button.md +57 -0
  9. data/docs/components/flow_button.md +102 -0
  10. data/docs/components/url_button.md +57 -0
  11. data/docs/messages/README.md +2 -1
  12. data/docs/messages/flow.md +241 -5
  13. data/docs/messages/interactive_call_to_action_url.md +9 -9
  14. data/docs/messages/interactive_list.md +2 -2
  15. data/docs/messages/interactive_reply_button.md +9 -9
  16. data/docs/messages/template.md +373 -0
  17. data/docs/resources/README.md +14 -0
  18. data/docs/resources/currency.md +22 -0
  19. data/docs/resources/date_time.md +11 -0
  20. data/docs/resources/text.md +9 -0
  21. data/docs/setup.md +45 -1
  22. data/examples/audio.rb +10 -10
  23. data/examples/document.rb +34 -34
  24. data/examples/image.rb +22 -22
  25. data/examples/interactive_call_to_action_url.rb +46 -46
  26. data/examples/interactive_list.rb +61 -61
  27. data/examples/interactive_reply_button.rb +43 -43
  28. data/examples/location.rb +32 -32
  29. data/examples/location_request.rb +11 -11
  30. data/examples/message.rb +8 -8
  31. data/examples/sticker.rb +10 -10
  32. data/examples/video.rb +22 -22
  33. data/examples/webhook.rb +77 -43
  34. data/lib/warb/category.rb +8 -0
  35. data/lib/warb/client.rb +7 -5
  36. data/lib/warb/components/action.rb +12 -8
  37. data/lib/warb/components/button.rb +29 -0
  38. data/lib/warb/components/component.rb +19 -0
  39. data/lib/warb/components/copy_code_button.rb +30 -0
  40. data/lib/warb/components/flow_button.rb +32 -0
  41. data/lib/warb/components/quick_reply_button.rb +15 -0
  42. data/lib/warb/components/url_button.rb +30 -0
  43. data/lib/warb/components/voice_call_button.rb +15 -0
  44. data/lib/warb/configuration.rb +4 -1
  45. data/lib/warb/connection.rb +15 -9
  46. data/lib/warb/dispatcher.rb +4 -3
  47. data/lib/warb/dispatcher_concern.rb +6 -0
  48. data/lib/warb/errors.rb +27 -0
  49. data/lib/warb/indicator_dispatcher.rb +4 -4
  50. data/lib/warb/language.rb +8 -0
  51. data/lib/warb/media_dispatcher.rb +10 -10
  52. data/lib/warb/resources/audio.rb +1 -1
  53. data/lib/warb/resources/contact.rb +22 -20
  54. data/lib/warb/resources/currency.rb +47 -0
  55. data/lib/warb/resources/date_time.rb +34 -0
  56. data/lib/warb/resources/document.rb +1 -1
  57. data/lib/warb/resources/flow.rb +82 -20
  58. data/lib/warb/resources/helpers/header.rb +35 -0
  59. data/lib/warb/resources/image.rb +1 -1
  60. data/lib/warb/resources/interactive_call_to_action_url.rb +10 -8
  61. data/lib/warb/resources/interactive_list.rb +7 -5
  62. data/lib/warb/resources/interactive_reply_button.rb +10 -8
  63. data/lib/warb/resources/location.rb +11 -1
  64. data/lib/warb/resources/location_request.rb +5 -3
  65. data/lib/warb/resources/reaction.rb +1 -1
  66. data/lib/warb/resources/resource.rb +14 -4
  67. data/lib/warb/resources/sticker.rb +1 -1
  68. data/lib/warb/resources/template.rb +163 -0
  69. data/lib/warb/resources/text.rb +31 -3
  70. data/lib/warb/resources/validation.rb +30 -0
  71. data/lib/warb/resources/video.rb +1 -1
  72. data/lib/warb/response.rb +33 -0
  73. data/lib/warb/response_error_handler.rb +42 -0
  74. data/lib/warb/template_dispatcher.rb +21 -0
  75. data/lib/warb/utils.rb +3 -1
  76. data/lib/warb/version.rb +1 -1
  77. data/lib/warb.rb +67 -31
  78. metadata +34 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58ff4cfa4904a9a820c4b5906b947b6f5dcbd3e5a3afa76a9e88ed3f83488bb8
4
- data.tar.gz: 1edcbcef65fd5f128cb0cf475f4b5c6ae8e4e285a4b57335b80818e0487f874a
3
+ metadata.gz: c7750b641ab09a5a2ecc79e894e4047a98af4602aebd98aad2edcdf61018142b
4
+ data.tar.gz: d9b0255c4f0a2c4bc6a6965f21459d971390b7722c4ffec3d2d7c533c649f611
5
5
  SHA512:
6
- metadata.gz: 43cabbb2bcd395dbbc32eacf0f170e00c5fa913f9edbe4543b9b19f81278648ccae955ac64601182fc468ab02ae81cdb81ae1c07d4601f793dd1645cad28a698
7
- data.tar.gz: f7ef031988f7c39be607047ebab9e56d627b848527fce0baa5043f1108a93e378e4e7b6d7df853240bcdba9ccb46b0c0c8ba135833fc31fbccaf01175dab9ba6
6
+ metadata.gz: d20edff3caa1f062d3c718cebd66dbf1a56392d51148ebe718fa25da9ec2869f8b1af2b82a515250740d5a6ce426064ee85b4db28f14bb27d13f99c919fe7d8a
7
+ data.tar.gz: 6507de0abb32ef0df3e4d37c1736209d6c85fb76fc890d352be7a9a71f0902f102a5b75f6b3ae11782eaf91e1797c7f10802f691c16e3412e93df8de4e4baddc
data/.rubocop.yml CHANGED
@@ -1,8 +1,15 @@
1
+ plugins:
2
+ - rubocop-rspec
3
+
1
4
  AllCops:
2
5
  TargetRubyVersion: 3.1
6
+ NewCops: enable
7
+ SuggestExtensions: false
8
+ Exclude:
9
+ - examples/**/*
10
+ - bin/*
11
+ Style/Documentation:
12
+ Enabled: false
3
13
 
4
- Style/StringLiterals:
5
- EnforcedStyle: double_quotes
6
-
7
- Style/StringLiteralsInInterpolation:
8
- EnforcedStyle: double_quotes
14
+ RSpec/NestedGroups:
15
+ Enabled: false
data/README.md CHANGED
@@ -9,18 +9,16 @@ A Ruby Gem focused on wrap all the functionalities and use cases of the WhatsApp
9
9
 
10
10
  ## Installation
11
11
 
12
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
12
+ Add `warb` to your bundle
13
13
 
14
- Install the gem and add to the application's Gemfile by executing:
15
-
16
- ```bash
17
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
14
+ ```ruby
15
+ bundle add warb
18
16
  ```
19
17
 
20
- If bundler is not being used to manage dependencies, install the gem by executing:
18
+ or add it manually to your Gemfile if you prefer.
21
19
 
22
- ```bash
23
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
20
+ ```ruby
21
+ gem 'warb'
24
22
  ```
25
23
 
26
24
  ## Configuration
@@ -90,9 +88,26 @@ Warb.message.dispatch(recipient_number) do |builder|
90
88
  end
91
89
  ```
92
90
 
91
+ ### What types of messages can I send?
92
+
93
+ Warb implements the main types of WhatsApp messages, you can follow the message types [`here`](docs/messages/README.md#messages-types)
94
+
95
+ examples:
96
+
97
+ ```ruby
98
+
99
+ warb = Warb.new(...)
100
+
101
+ warb.message.dispatch(...)
102
+ warb.audio.dispatch(...)
103
+ warb.video.dispatch(...)
104
+ warb.image.dispatch(...)
105
+ ...
106
+ ```
107
+
93
108
  ### Find all usage examples
94
109
 
95
- We suggest heading to the `examples/` directory, where you'll find documentation files with plenty of usage examples, organized by **Resources** (**Resources** are the types of messages you can send via WhatsApp using Warb).
110
+ We suggest heading to the [`examples`](examples) directory, where you'll find documentation files with plenty of usage examples, organized by **Resources** (**Resources** are the types of messages you can send via WhatsApp using Warb).
96
111
 
97
112
  You can also check the [`docs`](docs/README.md) for a more structured overview of the available resources and their usage.
98
113
 
@@ -109,6 +124,14 @@ To enable this kind of flow, you’ll need to know **when** a message is receive
109
124
  > ⚠️ **Note:** This gem **does not** provide built-in support for webhooks.
110
125
  > However, you can look at [`examples/webhook.rb`](examples/webhook.rb) for a starting point on how to implement it. Also, check the [official documentation](https://developers.facebook.com/docs/whatsapp/cloud-api/webhooks/payload-examples) for more details if you get stuck.
111
126
 
127
+ ## Deploy
128
+
129
+ ```
130
+ git tag v0.0.2
131
+ git push origin main --tags
132
+ ```
133
+
134
+
112
135
  ## Development
113
136
 
114
137
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- require "rubocop/rake_task"
8
+ require 'rubocop/rake_task'
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
data/docs/README.md CHANGED
@@ -10,4 +10,7 @@ Refer to [webhook](webhook.md) for more details on how to setup a webhook to get
10
10
  Refer to [messages](./messages/README.md) for more details on how to send messages using Warb.
11
11
 
12
12
  ## Components
13
- Refer to [components](./components/README.md) for more details on how Warb components work.
13
+ Refer to [components](./components/README.md) for more details on how Warb components work.
14
+
15
+ ## Resources
16
+ Refer to [resources](./resources/README.md) for more details on resources.
@@ -18,4 +18,7 @@ Here is a table of available components, and where they can be used:
18
18
  | `Warb::Components::ReplyButtonAction` | [Interactive Reply Button](../messages/interactive_reply_button.md) | [Reply Button Action](./reply_button_action) |
19
19
  | `Warb::Components::Row` | [Interactive List](../messages/interactive_list.md) | [Row](./row.md) |
20
20
  | `Warb::Components::ListAction` | [Interactive List](../messages/interactive_list.md) | [List Action](./list_action.md) |
21
- | `Warb::Components::Section` | [Interactive List](../messages/interactive_list.md) | [Section](./section.md) |
21
+ | `Warb::Components::Section` | [Interactive List](../messages/interactive_list.md) | [Section](./section.md) |
22
+ | `Warb::Components::Button` | [Template](../messages/template.md) | [Button](./button.md) |
23
+ | `Warb::Components::UrlButton` | [Template](../messages/template.md) | [UrlButton](./url_button.md) |
24
+ | `Warb::Components::CopyCodeButton` | [Template](../messages/template.md) | [CopyCodeButton](./copy_code_button.md) |
@@ -0,0 +1,62 @@
1
+ # Button
2
+
3
+ `Warb::Components::Button` is a component that represents a generic button used in template messages. It's part of the Components module, which contains reusable parts of complex structures.
4
+
5
+ It represents a generic button, which can be set with the following attributes:
6
+
7
+ ## Attributes
8
+ | Attribute | Type | Required | Description |
9
+ |--------------|-----------|----------|-----------------------------------------------|
10
+ | `index` | `Integer` | Yes | An identifier or position for the button. |
11
+ | `sub_type` | `String` | Yes | A more specific classification for the button |
12
+
13
+ ## Common Button Types
14
+ | Button Type | Template Instance Method | Params |
15
+ |---------------|------------------------------|------------------------------------------|
16
+ | `quick_reply` | `add_quick_reply_button` | `index` |
17
+ | `voice_call` | `add_voice_call_button` | `index` |
18
+ | `url` | `add_dynamic_url_button` | `index`, `text` |
19
+ | `copy_code` | `add_copy_code_button` | `index`, `coupon_code` |
20
+ | `flow` | `add_flow_button` | `index`, `flow_token`, `flow_action_data`|
21
+
22
+ Please, refer to our [templates messaging documentation](../messages/template.md) for more info. You can check the methods to insert a button in the "Adding Buttons" section.
23
+
24
+ ## Examples
25
+
26
+ ### Quick Reply button
27
+ ```ruby
28
+ quick_reply = Warb::Components::Button.new(index: 0, sub_type: "quick_reply")
29
+ quick_reply.to_h
30
+ => {
31
+ type: "button",
32
+ sub_type: "quick_reply",
33
+ index: 0
34
+ }
35
+ ```
36
+
37
+ ### Voice Call button
38
+ ```ruby
39
+ voice_call = Warb::Components::Button.new(index: 1, sub_type: "voice_call")
40
+ voice_call.to_h
41
+ => {
42
+ type: "button",
43
+ sub_type: "voice_call",
44
+ index: 1
45
+ }
46
+ ```
47
+
48
+ ## Usage in Templates
49
+
50
+ Buttons are typically used within template messages. Here's how to add them:
51
+
52
+ ```ruby
53
+ template = Warb::Resources::Template.new(name: "my_template", language: "en_US")
54
+
55
+ # Add a quick reply button
56
+ template.add_quick_reply_button(index: 0)
57
+
58
+ # Add a voice call button
59
+ template.add_voice_call_button(index: 1)
60
+
61
+ # The buttons will be included in the template's build_payload (as components)
62
+ ```
@@ -0,0 +1,57 @@
1
+ # CopyCodeButton
2
+
3
+ `Warb::Components::CopyCodeButton` is a component used in template messages for copy code buttons.
4
+
5
+ ## Attributes
6
+ | Attribute | Type | Required | Description |
7
+ |----------------|-----------|----------|-----------------------------------------------|
8
+ | `index` | `Integer` | Yes | An identifier or position for the button. |
9
+ | `sub_type` | `String` | Yes | Always "copy_code" for this button type |
10
+ | `coupon_code` | `String` | No | The coupon code to be copied when button is pressed |
11
+
12
+ ## Examples
13
+
14
+ ### Basic copy code button
15
+ ```ruby
16
+ copy_button = Warb::Components::CopyCodeButton.new(index: 0, sub_type: "copy_code", coupon_code: "SAVE20")
17
+ copy_button.to_h
18
+ => {
19
+ type: "button",
20
+ sub_type: "copy_code",
21
+ index: 0,
22
+ parameters: [
23
+ {
24
+ type: "coupon_code",
25
+ coupon_code: "SAVE20"
26
+ }
27
+ ]
28
+ }
29
+ ```
30
+
31
+ ### Copy code button without coupon code
32
+ ```ruby
33
+ copy_button = Warb::Components::CopyCodeButton.new(index: 1, sub_type: "copy_code")
34
+ copy_button.to_h
35
+ => {
36
+ type: "button",
37
+ sub_type: "copy_code",
38
+ index: 1
39
+ }
40
+ ```
41
+
42
+ ## Usage in Templates
43
+
44
+ Copy code buttons are typically added to templates using the `add_copy_code_button` method:
45
+
46
+ ```ruby
47
+ template = Warb::Resources::Template.new(name: "my_template", language: "en_US")
48
+
49
+ # Add a copy code button
50
+ template.add_copy_code_button(index: 0, coupon_code: "SAVE20")
51
+
52
+ # Or using a block for more complex configuration
53
+ template.add_copy_code_button do |button|
54
+ button.index = 0
55
+ button.coupon_code = "SAVE20"
56
+ end
57
+ ```
@@ -0,0 +1,102 @@
1
+ # FlowButton
2
+
3
+ ```Warb::Components::FlowButton``` is a component used in template messages for flow buttons.
4
+ This button type allows you to link a template directly with a WhatsApp Flow experience.
5
+
6
+ ## Attributes
7
+ | Attribute | Type | Required | Description |
8
+ | ------------------ | --------- | -------- |-----------------------------------------------------------------|
9
+ | `index` | `Integer` | Yes | An identifier or position for the button in the template. |
10
+ | `sub_type` | `String` | Yes | Always `"flow"` for this button type. |
11
+ | `flow_token` | `String` | No | If not set, the API defaults to `"unused"`. |
12
+ | `flow_action_data` | `Hash` | No | A key-value payload passed to the flow as pre-filled form data. |
13
+
14
+
15
+
16
+ ## Examples
17
+ ###### Basic Flow button with token
18
+ ```ruby
19
+ flow_button = Warb::Components::FlowButton.new(
20
+ index: 0,
21
+ sub_type: "flow",
22
+ flow_token: "TOKEN_123"
23
+ )
24
+
25
+ flow_button.to_h
26
+ => {
27
+ type: "button",
28
+ sub_type: "flow",
29
+ index: 0,
30
+ parameters: [
31
+ {
32
+ type: "action",
33
+ action: {
34
+ flow_token: "TOKEN_123"
35
+ }
36
+ }
37
+ ]
38
+ }
39
+ ```
40
+
41
+ ##### Flow button with token and action data
42
+ ```ruby
43
+ flow_button = Warb::Components::FlowButton.new(
44
+ index: 1,
45
+ sub_type: "flow",
46
+ flow_token: "TOKEN_ABC",
47
+ flow_action_data: { name: "John", cpf: "11122233344" }
48
+ )
49
+
50
+ flow_button.to_h
51
+ => {
52
+ type: "button",
53
+ sub_type: "flow",
54
+ index: 1,
55
+ parameters: [
56
+ {
57
+ type: "action",
58
+ action: {
59
+ flow_token: "TOKEN_ABC",
60
+ flow_action_data: { name: "John", cpf: "11122233344" }
61
+ }
62
+ }
63
+ ]
64
+ }
65
+ ```
66
+
67
+ ##### Flow button without optional fields
68
+ ```ruby
69
+ flow_button = Warb::Components::FlowButton.new(index: 2, sub_type: "flow")
70
+ flow_button.to_h
71
+ => {
72
+ type: "button",
73
+ sub_type: "flow",
74
+ index: 2,
75
+ parameters: [
76
+ {
77
+ type: "action",
78
+ action: {}
79
+ }
80
+ ]
81
+ }
82
+ ```
83
+ ### Usage in Templates
84
+
85
+ Flow buttons are typically added to templates using the add_flow_button method:
86
+
87
+ ```ruby
88
+ template = Warb::Resources::Template.new(name: "my_template", language: "en_US")
89
+
90
+ # Add a flow button with token
91
+ template.add_flow_button(index: 0, flow_token: "TOKEN_123")
92
+
93
+ # Add a flow button with token and action data
94
+ template.add_flow_button(index: 1, flow_token: "TOKEN_ABC", flow_action_data: { name: "Jane", dob: "1990-01-01" })
95
+
96
+ # Or using a block for more complex configuration
97
+ template.add_flow_button do |button|
98
+ button.index = 0
99
+ button.flow_token = "TOKEN_DYNAMIC"
100
+ button.flow_action_data = { email: "user@example.com" }
101
+ end
102
+ ```
@@ -0,0 +1,57 @@
1
+ # UrlButton
2
+
3
+ `Warb::Components::UrlButton` is a component used in template messages, for dynamic url or auth code buttons.
4
+
5
+ ## Attributes
6
+ | Attribute | Type | Required | Description |
7
+ |--------------|-----------|----------|-----------------------------------------------|
8
+ | `index` | `Integer` | Yes | An identifier or position for the button. |
9
+ | `sub_type` | `String` | Yes | Always "url" for this button type |
10
+ | `text` | `String` | No | The URL suffix or text parameter for the button |
11
+
12
+ ## Examples
13
+
14
+ ### Basic URL button
15
+ ```ruby
16
+ url_button = Warb::Components::UrlButton.new(index: 0, sub_type: "url", text: "example.com")
17
+ url_button.to_h
18
+ => {
19
+ type: "button",
20
+ sub_type: "url",
21
+ index: 0,
22
+ parameters: [
23
+ {
24
+ type: "text",
25
+ text: "example.com"
26
+ }
27
+ ]
28
+ }
29
+ ```
30
+
31
+ ### URL button without text parameter
32
+ ```ruby
33
+ url_button = Warb::Components::UrlButton.new(index: 1, sub_type: "url")
34
+ url_button.to_h
35
+ => {
36
+ type: "button",
37
+ sub_type: "url",
38
+ index: 1
39
+ }
40
+ ```
41
+
42
+ ## Usage in Templates
43
+
44
+ URL buttons are typically added to templates using the `add_dynamic_url_button` method:
45
+
46
+ ```ruby
47
+ template = Warb::Resources::Template.new(name: "my_template", language: "en_US")
48
+
49
+ # Add a dynamic URL button
50
+ template.add_dynamic_url_button(index: 0, text: "example.com")
51
+
52
+ # Or using a block for more complex configuration
53
+ template.add_dynamic_url_button do |button|
54
+ button.index = 0
55
+ button.text = "example.com"
56
+ end
57
+ ```
@@ -71,9 +71,10 @@ Messages are sent using a helper dispatcher and its resource class. Here is a li
71
71
  | Video | `Warb::Resources::Video` | `video` | [Video Message](./video.md) |
72
72
  | Special Dispatchers |
73
73
  | Indicator | `Warb::Resources::Indicator` | `indicator` | [Indicator Message](./indicator.md) |
74
+ | Template | `Warb::Resources::Template` | `template` | [Template Message](./template.md) |
74
75
 
75
76
  > Simple Dispatcher doesn't offer any additional functionality, they just send messages.
76
77
 
77
78
  > Media Dispatchers, aside from sending messages, also provide methods to upload and download media files.
78
79
 
79
- > Special Dispatchers are used for specific purposes, such as sending indicators or reactions.
80
+ > Special Dispatchers are used for specific purposes, such as sending indicators, reactions or templates.
@@ -1,12 +1,248 @@
1
1
  # Flow
2
2
 
3
- Flow is a special type of message. We can summarize it simply as a form.
3
+ Flow is a special type of interactive WhatsApp message that provides a "form-like" experience.
4
+ With ```Warb.flow``` you can send static (navigate) or dynamic (data exchange) flows, both in draft and published modes.
4
5
 
5
- At this point of writing, this gem only supports sending existing flows, and it can only send flows which are in draft.
6
+ Prerequisites (Meta)
7
+ Business Account + Developer Account
8
+ Verified Business to send flows in production WhatsApp (unverified accounts can only test in Meta’s Flow editor)
9
+ For dynamic flows: endpoint + encryption configured in Meta (to handle user responses)
6
10
 
7
- To send flows, you can do as following:
11
+ ### Quick Examples
12
+
13
+ ##### Send a static draft flow:
14
+ ```ruby
15
+ Warb.flow.dispatch(recipient_number, flow_id: "0000000000000000", mode: "draft", screen: "INITIAL", body: "Open flow")
16
+ ```
17
+
18
+ ##### Send a dynamic draft flow:
19
+ ```ruby
20
+ Warb.flow.dispatch(recipient_number,
21
+ flow_id: "0000000000000000",
22
+ mode: "draft",
23
+ flow_action: "data_exchange",
24
+ body: "Open flow"
25
+ )
26
+ ```
27
+
28
+ ##### Send a dynamic published flow with custom header, body, and footer:
29
+ ```ruby
30
+ Warb.flow.dispatch(recipient_number) do |flow|
31
+ flow.flow_id = "0000000000000000"
32
+ flow.flow_action = "data_exchange"
33
+ flow.mode = "published"
34
+ flow.body = "Hello! Please follow the instructions."
35
+ flow.footer = "Need help? Reply to this message."
36
+
37
+ flow.header = {
38
+ type: "document",
39
+ document: {
40
+ link: "https://example.com/contract.pdf",
41
+ filename: "contract.pdf"
42
+ }
43
+ }
44
+
45
+ flow.flow_cta = "Sign"
46
+ end
47
+ ```
48
+
49
+ ### Dispatching Flow Messages
8
50
  ```ruby
9
- Warb.flow.dispatch(recipient_number, flow_id: "flow_id", screen: "screen")
51
+ Warb.flow.dispatch(recipient_number, **params, &block)
10
52
  ```
53
+ ##### Parameters
54
+ | Attribute | Type | Required | Description |
55
+ | ------------- | -------- | ---------------------------------- | ----------------------------------------------------------- |
56
+ | `flow_id` | `String` | Yes | The ID of the Flow created in Meta. |
57
+ | `body` | `String` | Yes | Body text shown in the Flow message. |
58
+ | `flow_action` | `String` | No | `"navigate"` (default) or `"data_exchange"`. |
59
+ | `mode` | `String` | Yes if `flow mode == 'draft'` | `"published"` (default) or `"draft"`. |
60
+ | `screen` | `String` | Yes if `flow_action == "navigate"` | Initial screen to navigate to. |
61
+ | `flow_cta` | `String` | No | Label for the button that opens the Flow. |
62
+ | `flow_token` | `String` | No | Token for dynamic flows (encryption/validation). |
63
+ | `data` | `Hash` | No | Prefill data for navigate flows. |
64
+ | `header` | `Hash` | No | Optional header (see below). |
65
+ | `footer` | `String` | No | Optional footer text. |
66
+
67
+ ### Supported Headers
68
+
69
+ You must provide exactly one of the following header types:
11
70
 
12
- `flow_id` must be the ID of the flow and `screen` must be the ID of the first screen of the flow.
71
+ ##### Text
72
+ ```ruby
73
+ { type: "text", text: "Flow title" }
74
+ ```
75
+
76
+ ##### Image
77
+ ```ruby
78
+ { type: "image", image: { id: "MEDIA_ID" } }
79
+ # or
80
+ { type: "image", image: { link: "https://example.com/img.jpg" } }
81
+ ```
82
+
83
+ ##### Video
84
+ ```ruby
85
+ { type: "video", video: { id: "MEDIA_ID" } }
86
+ # or
87
+ { type: "video", video: { link: "https://example.com/video.mp4" } }
88
+ ```
89
+
90
+ ##### Document
91
+ ```ruby
92
+ { type: "document", document: { id: "MEDIA_ID" } }
93
+ # or
94
+ { type: "document", document: { link: "https://example.com/file.pdf", filename: "file.pdf" } }
95
+ ```
96
+
97
+ ##### Note:
98
+
99
+ id must be obtained from a media upload (Warb.image/video/document.upload).
100
+
101
+ link must be a public URL. For documents, filename is required to determine preview capabilities.
102
+
103
+ ### Modes and Actions
104
+ ##### mode
105
+
106
+ "published" (default): Published flow. Allows customizing header, body, footer, and flow_cta.
107
+
108
+ "draft": Draft flow. Usable via Meta Flow editor and sometimes on WhatsApp, but some elements (like body text and CTA) may be restricted.
109
+
110
+ ##### flow_action
111
+
112
+ "navigate" (default) → static flow
113
+ Requires screen, can include initial data:
114
+ ```ruby
115
+ Warb.flow.dispatch(recipient_number,
116
+ flow_id: "0000000000000000",
117
+ screen: "INITIAL",
118
+ body: "Continue",
119
+ data: { prefill: { name: "Alice", email: "alice@example.com" } }
120
+ )
121
+ ```
122
+
123
+ "data_exchange" → dynamic flow
124
+ No flow_action_payload (omitted automatically):
125
+ ```ruby
126
+ Warb.flow.dispatch(recipient_number,
127
+ flow_id: "0000000000000000",
128
+ flow_action: "data_exchange",
129
+ body: "Fill the form",
130
+ )
131
+ ```
132
+
133
+ ### Block Building
134
+
135
+ You can also build flows using a block:
136
+ ```ruby
137
+ Warb.flow.dispatch(recipient_number) do |flow|
138
+ flow.flow_id = "0000000000000000"
139
+ flow.flow_action = "data_exchange"
140
+ flow.mode = "published"
141
+ flow.body = "We need some information"
142
+
143
+ flow.header = { type: "text", text: "Registration" }
144
+ flow.footer = "Thanks!"
145
+
146
+ flow.flow_cta = "Open"
147
+ end
148
+ ```
149
+
150
+ ### Validations
151
+
152
+ Before sending, the gem enforces:
153
+
154
+ flow_id is required → raises ArgumentError: flow_id is required
155
+
156
+ body is required → raises ArgumentError: body is required for flow message
157
+
158
+ If flow_action == "navigate" then screen is required →
159
+ raises ArgumentError: screen is required for flow_action=navigate
160
+
161
+ The Meta API may return additional errors (invalid parameters, missing fields, etc.), which are raised as Warb::BadRequest, Warb::RequestError, etc.
162
+
163
+ Example Scenarios
164
+ 1) Static / Draft
165
+ ```ruby
166
+ Warb.flow.dispatch(recipient_number,
167
+ flow_id: "0000000000000000",
168
+ screen: "INITIAL",
169
+ mode: "draft",
170
+ body: "Open flow"
171
+ )
172
+ ```
173
+
174
+ 2) Dynamic / Draft
175
+ ```ruby
176
+ Warb.flow.dispatch(recipient_number,
177
+ flow_id: "0000000000000000",
178
+ flow_action: "data_exchange",
179
+ mode: "draft",
180
+ body: "Fill the form"
181
+ )
182
+ ```
183
+
184
+ 3) Dynamic / Published with Document Header
185
+ ```ruby
186
+ Warb.flow.dispatch(recipient_number) do |flow|
187
+ flow.flow_id = "0000000000000000"
188
+ flow.flow_action = "data_exchange"
189
+ flow.mode = "published"
190
+ flow.body = "Please review and sign the document."
191
+ flow.footer = "Reply if you need assistance."
192
+ flow.flow_cta = "Sign"
193
+
194
+ flow.header = {
195
+ type: "document",
196
+ document: {
197
+ link: "https://www.thecampusqdl.com/uploads/files/pdf_sample_2.pdf",
198
+ filename: "pdf_sample_2.pdf"
199
+ }
200
+ }
201
+ end
202
+ ```
203
+
204
+ 4) Static / Published with Image Header (id) and Prefill Data
205
+ ```ruby
206
+ image_id = Warb.image.upload(file_path: "banner.jpg", file_type: "image/jpeg")
207
+
208
+ Warb.flow.dispatch(recipient_number) do |flow|
209
+ flow.flow_id = "0000000000000000"
210
+ flow.mode = "published"
211
+ flow.body = "Open and check your data"
212
+
213
+ flow.header = { type: "image", image: { id: image_id } }
214
+
215
+ flow.screen = "INITIAL"
216
+ flow.data = { prefill: { name: "John", email: "john@example.com" } }
217
+ end
218
+ ```
219
+
220
+ ### Generated Payload (Reference)
221
+
222
+ Example payload produced by the gem:
223
+ ```ruby
224
+ {
225
+ "type": "interactive",
226
+ "interactive": {
227
+ "type": "flow",
228
+ "header": { ... },
229
+ "body": { "text": "..." },
230
+ "footer": { "text": "..." },
231
+ "action": {
232
+ "name": "flow",
233
+ "parameters": {
234
+ "flow_message_version": "3",
235
+ "flow_id": "....",
236
+ "flow_action": "navigate" | "data_exchange",
237
+ "mode": "published" | "draft",
238
+ "flow_cta": "Open",
239
+ "flow_token": "TOKEN",
240
+ "flow_action_payload": {
241
+ "screen": "INITIAL",
242
+ "data": { "prefill": { ... } }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }
248
+ ```