wappa 0.1.0__py3-none-any.whl

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.

Potentially problematic release.


This version of wappa might be problematic. Click here for more details.

Files changed (211) hide show
  1. wappa/__init__.py +85 -0
  2. wappa/api/__init__.py +1 -0
  3. wappa/api/controllers/__init__.py +10 -0
  4. wappa/api/controllers/webhook_controller.py +441 -0
  5. wappa/api/dependencies/__init__.py +15 -0
  6. wappa/api/dependencies/whatsapp_dependencies.py +220 -0
  7. wappa/api/dependencies/whatsapp_media_dependencies.py +26 -0
  8. wappa/api/middleware/__init__.py +7 -0
  9. wappa/api/middleware/error_handler.py +158 -0
  10. wappa/api/middleware/owner.py +99 -0
  11. wappa/api/middleware/request_logging.py +184 -0
  12. wappa/api/routes/__init__.py +6 -0
  13. wappa/api/routes/health.py +102 -0
  14. wappa/api/routes/webhooks.py +211 -0
  15. wappa/api/routes/whatsapp/__init__.py +15 -0
  16. wappa/api/routes/whatsapp/whatsapp_interactive.py +429 -0
  17. wappa/api/routes/whatsapp/whatsapp_media.py +440 -0
  18. wappa/api/routes/whatsapp/whatsapp_messages.py +195 -0
  19. wappa/api/routes/whatsapp/whatsapp_specialized.py +516 -0
  20. wappa/api/routes/whatsapp/whatsapp_templates.py +431 -0
  21. wappa/api/routes/whatsapp_combined.py +35 -0
  22. wappa/cli/__init__.py +9 -0
  23. wappa/cli/main.py +199 -0
  24. wappa/core/__init__.py +6 -0
  25. wappa/core/config/__init__.py +5 -0
  26. wappa/core/config/settings.py +161 -0
  27. wappa/core/events/__init__.py +41 -0
  28. wappa/core/events/default_handlers.py +642 -0
  29. wappa/core/events/event_dispatcher.py +244 -0
  30. wappa/core/events/event_handler.py +247 -0
  31. wappa/core/events/webhook_factory.py +219 -0
  32. wappa/core/factory/__init__.py +15 -0
  33. wappa/core/factory/plugin.py +68 -0
  34. wappa/core/factory/wappa_builder.py +326 -0
  35. wappa/core/logging/__init__.py +5 -0
  36. wappa/core/logging/context.py +100 -0
  37. wappa/core/logging/logger.py +343 -0
  38. wappa/core/plugins/__init__.py +34 -0
  39. wappa/core/plugins/auth_plugin.py +169 -0
  40. wappa/core/plugins/cors_plugin.py +128 -0
  41. wappa/core/plugins/custom_middleware_plugin.py +182 -0
  42. wappa/core/plugins/database_plugin.py +235 -0
  43. wappa/core/plugins/rate_limit_plugin.py +183 -0
  44. wappa/core/plugins/redis_plugin.py +224 -0
  45. wappa/core/plugins/wappa_core_plugin.py +261 -0
  46. wappa/core/plugins/webhook_plugin.py +253 -0
  47. wappa/core/types.py +108 -0
  48. wappa/core/wappa_app.py +546 -0
  49. wappa/database/__init__.py +18 -0
  50. wappa/database/adapter.py +107 -0
  51. wappa/database/adapters/__init__.py +17 -0
  52. wappa/database/adapters/mysql_adapter.py +187 -0
  53. wappa/database/adapters/postgresql_adapter.py +169 -0
  54. wappa/database/adapters/sqlite_adapter.py +174 -0
  55. wappa/domain/__init__.py +28 -0
  56. wappa/domain/builders/__init__.py +5 -0
  57. wappa/domain/builders/message_builder.py +189 -0
  58. wappa/domain/entities/__init__.py +5 -0
  59. wappa/domain/enums/messenger_platform.py +123 -0
  60. wappa/domain/factories/__init__.py +6 -0
  61. wappa/domain/factories/media_factory.py +450 -0
  62. wappa/domain/factories/message_factory.py +497 -0
  63. wappa/domain/factories/messenger_factory.py +244 -0
  64. wappa/domain/interfaces/__init__.py +32 -0
  65. wappa/domain/interfaces/base_repository.py +94 -0
  66. wappa/domain/interfaces/cache_factory.py +85 -0
  67. wappa/domain/interfaces/cache_interface.py +199 -0
  68. wappa/domain/interfaces/expiry_repository.py +68 -0
  69. wappa/domain/interfaces/media_interface.py +311 -0
  70. wappa/domain/interfaces/messaging_interface.py +523 -0
  71. wappa/domain/interfaces/pubsub_repository.py +151 -0
  72. wappa/domain/interfaces/repository_factory.py +108 -0
  73. wappa/domain/interfaces/shared_state_repository.py +122 -0
  74. wappa/domain/interfaces/state_repository.py +123 -0
  75. wappa/domain/interfaces/tables_repository.py +215 -0
  76. wappa/domain/interfaces/user_repository.py +114 -0
  77. wappa/domain/interfaces/webhooks/__init__.py +1 -0
  78. wappa/domain/models/media_result.py +110 -0
  79. wappa/domain/models/platforms/__init__.py +15 -0
  80. wappa/domain/models/platforms/platform_config.py +104 -0
  81. wappa/domain/services/__init__.py +11 -0
  82. wappa/domain/services/tenant_credentials_service.py +56 -0
  83. wappa/messaging/__init__.py +7 -0
  84. wappa/messaging/whatsapp/__init__.py +1 -0
  85. wappa/messaging/whatsapp/client/__init__.py +5 -0
  86. wappa/messaging/whatsapp/client/whatsapp_client.py +417 -0
  87. wappa/messaging/whatsapp/handlers/__init__.py +13 -0
  88. wappa/messaging/whatsapp/handlers/whatsapp_interactive_handler.py +653 -0
  89. wappa/messaging/whatsapp/handlers/whatsapp_media_handler.py +579 -0
  90. wappa/messaging/whatsapp/handlers/whatsapp_specialized_handler.py +434 -0
  91. wappa/messaging/whatsapp/handlers/whatsapp_template_handler.py +416 -0
  92. wappa/messaging/whatsapp/messenger/__init__.py +5 -0
  93. wappa/messaging/whatsapp/messenger/whatsapp_messenger.py +904 -0
  94. wappa/messaging/whatsapp/models/__init__.py +61 -0
  95. wappa/messaging/whatsapp/models/basic_models.py +65 -0
  96. wappa/messaging/whatsapp/models/interactive_models.py +287 -0
  97. wappa/messaging/whatsapp/models/media_models.py +215 -0
  98. wappa/messaging/whatsapp/models/specialized_models.py +304 -0
  99. wappa/messaging/whatsapp/models/template_models.py +261 -0
  100. wappa/persistence/cache_factory.py +93 -0
  101. wappa/persistence/json/__init__.py +14 -0
  102. wappa/persistence/json/cache_adapters.py +271 -0
  103. wappa/persistence/json/handlers/__init__.py +1 -0
  104. wappa/persistence/json/handlers/state_handler.py +250 -0
  105. wappa/persistence/json/handlers/table_handler.py +263 -0
  106. wappa/persistence/json/handlers/user_handler.py +213 -0
  107. wappa/persistence/json/handlers/utils/__init__.py +1 -0
  108. wappa/persistence/json/handlers/utils/file_manager.py +153 -0
  109. wappa/persistence/json/handlers/utils/key_factory.py +11 -0
  110. wappa/persistence/json/handlers/utils/serialization.py +121 -0
  111. wappa/persistence/json/json_cache_factory.py +76 -0
  112. wappa/persistence/json/storage_manager.py +285 -0
  113. wappa/persistence/memory/__init__.py +14 -0
  114. wappa/persistence/memory/cache_adapters.py +271 -0
  115. wappa/persistence/memory/handlers/__init__.py +1 -0
  116. wappa/persistence/memory/handlers/state_handler.py +250 -0
  117. wappa/persistence/memory/handlers/table_handler.py +280 -0
  118. wappa/persistence/memory/handlers/user_handler.py +213 -0
  119. wappa/persistence/memory/handlers/utils/__init__.py +1 -0
  120. wappa/persistence/memory/handlers/utils/key_factory.py +11 -0
  121. wappa/persistence/memory/handlers/utils/memory_store.py +317 -0
  122. wappa/persistence/memory/handlers/utils/ttl_manager.py +235 -0
  123. wappa/persistence/memory/memory_cache_factory.py +76 -0
  124. wappa/persistence/memory/storage_manager.py +235 -0
  125. wappa/persistence/redis/README.md +699 -0
  126. wappa/persistence/redis/__init__.py +11 -0
  127. wappa/persistence/redis/cache_adapters.py +285 -0
  128. wappa/persistence/redis/ops.py +880 -0
  129. wappa/persistence/redis/redis_cache_factory.py +71 -0
  130. wappa/persistence/redis/redis_client.py +231 -0
  131. wappa/persistence/redis/redis_handler/__init__.py +26 -0
  132. wappa/persistence/redis/redis_handler/state_handler.py +176 -0
  133. wappa/persistence/redis/redis_handler/table.py +158 -0
  134. wappa/persistence/redis/redis_handler/user.py +138 -0
  135. wappa/persistence/redis/redis_handler/utils/__init__.py +12 -0
  136. wappa/persistence/redis/redis_handler/utils/key_factory.py +32 -0
  137. wappa/persistence/redis/redis_handler/utils/serde.py +146 -0
  138. wappa/persistence/redis/redis_handler/utils/tenant_cache.py +268 -0
  139. wappa/persistence/redis/redis_manager.py +189 -0
  140. wappa/processors/__init__.py +6 -0
  141. wappa/processors/base_processor.py +262 -0
  142. wappa/processors/factory.py +550 -0
  143. wappa/processors/whatsapp_processor.py +810 -0
  144. wappa/schemas/__init__.py +6 -0
  145. wappa/schemas/core/__init__.py +71 -0
  146. wappa/schemas/core/base_message.py +499 -0
  147. wappa/schemas/core/base_status.py +322 -0
  148. wappa/schemas/core/base_webhook.py +312 -0
  149. wappa/schemas/core/types.py +253 -0
  150. wappa/schemas/core/webhook_interfaces/__init__.py +48 -0
  151. wappa/schemas/core/webhook_interfaces/base_components.py +293 -0
  152. wappa/schemas/core/webhook_interfaces/universal_webhooks.py +348 -0
  153. wappa/schemas/factory.py +754 -0
  154. wappa/schemas/webhooks/__init__.py +3 -0
  155. wappa/schemas/whatsapp/__init__.py +6 -0
  156. wappa/schemas/whatsapp/base_models.py +285 -0
  157. wappa/schemas/whatsapp/message_types/__init__.py +93 -0
  158. wappa/schemas/whatsapp/message_types/audio.py +350 -0
  159. wappa/schemas/whatsapp/message_types/button.py +267 -0
  160. wappa/schemas/whatsapp/message_types/contact.py +464 -0
  161. wappa/schemas/whatsapp/message_types/document.py +421 -0
  162. wappa/schemas/whatsapp/message_types/errors.py +195 -0
  163. wappa/schemas/whatsapp/message_types/image.py +424 -0
  164. wappa/schemas/whatsapp/message_types/interactive.py +430 -0
  165. wappa/schemas/whatsapp/message_types/location.py +416 -0
  166. wappa/schemas/whatsapp/message_types/order.py +372 -0
  167. wappa/schemas/whatsapp/message_types/reaction.py +271 -0
  168. wappa/schemas/whatsapp/message_types/sticker.py +328 -0
  169. wappa/schemas/whatsapp/message_types/system.py +317 -0
  170. wappa/schemas/whatsapp/message_types/text.py +411 -0
  171. wappa/schemas/whatsapp/message_types/unsupported.py +273 -0
  172. wappa/schemas/whatsapp/message_types/video.py +344 -0
  173. wappa/schemas/whatsapp/status_models.py +479 -0
  174. wappa/schemas/whatsapp/validators.py +454 -0
  175. wappa/schemas/whatsapp/webhook_container.py +438 -0
  176. wappa/webhooks/__init__.py +17 -0
  177. wappa/webhooks/core/__init__.py +71 -0
  178. wappa/webhooks/core/base_message.py +499 -0
  179. wappa/webhooks/core/base_status.py +322 -0
  180. wappa/webhooks/core/base_webhook.py +312 -0
  181. wappa/webhooks/core/types.py +253 -0
  182. wappa/webhooks/core/webhook_interfaces/__init__.py +48 -0
  183. wappa/webhooks/core/webhook_interfaces/base_components.py +293 -0
  184. wappa/webhooks/core/webhook_interfaces/universal_webhooks.py +441 -0
  185. wappa/webhooks/factory.py +754 -0
  186. wappa/webhooks/whatsapp/__init__.py +6 -0
  187. wappa/webhooks/whatsapp/base_models.py +285 -0
  188. wappa/webhooks/whatsapp/message_types/__init__.py +93 -0
  189. wappa/webhooks/whatsapp/message_types/audio.py +350 -0
  190. wappa/webhooks/whatsapp/message_types/button.py +267 -0
  191. wappa/webhooks/whatsapp/message_types/contact.py +464 -0
  192. wappa/webhooks/whatsapp/message_types/document.py +421 -0
  193. wappa/webhooks/whatsapp/message_types/errors.py +195 -0
  194. wappa/webhooks/whatsapp/message_types/image.py +424 -0
  195. wappa/webhooks/whatsapp/message_types/interactive.py +430 -0
  196. wappa/webhooks/whatsapp/message_types/location.py +416 -0
  197. wappa/webhooks/whatsapp/message_types/order.py +372 -0
  198. wappa/webhooks/whatsapp/message_types/reaction.py +271 -0
  199. wappa/webhooks/whatsapp/message_types/sticker.py +328 -0
  200. wappa/webhooks/whatsapp/message_types/system.py +317 -0
  201. wappa/webhooks/whatsapp/message_types/text.py +411 -0
  202. wappa/webhooks/whatsapp/message_types/unsupported.py +273 -0
  203. wappa/webhooks/whatsapp/message_types/video.py +344 -0
  204. wappa/webhooks/whatsapp/status_models.py +479 -0
  205. wappa/webhooks/whatsapp/validators.py +454 -0
  206. wappa/webhooks/whatsapp/webhook_container.py +438 -0
  207. wappa-0.1.0.dist-info/METADATA +269 -0
  208. wappa-0.1.0.dist-info/RECORD +211 -0
  209. wappa-0.1.0.dist-info/WHEEL +4 -0
  210. wappa-0.1.0.dist-info/entry_points.txt +2 -0
  211. wappa-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,429 @@
1
+ """
2
+ WhatsApp interactive messaging API endpoints.
3
+
4
+ Provides REST API endpoints for WhatsApp interactive operations:
5
+ - POST /api/whatsapp/interactive/send-buttons: Send button messages
6
+ - POST /api/whatsapp/interactive/send-list: Send list messages
7
+ - POST /api/whatsapp/interactive/send-cta: Send call-to-action messages
8
+ - GET /api/whatsapp/interactive/health: Service health check
9
+
10
+ Router configuration:
11
+ - Prefix: /whatsapp/interactive
12
+ - Tags: ["WhatsApp - Interactive"]
13
+ - Full URL: /api/whatsapp/interactive/ (when included with /api prefix)
14
+ """
15
+
16
+ from fastapi import APIRouter, Depends, HTTPException
17
+
18
+ from wappa.api.dependencies.whatsapp_dependencies import get_whatsapp_messenger
19
+ from wappa.domain.interfaces.messaging_interface import IMessenger
20
+ from wappa.messaging.whatsapp.models.basic_models import MessageResult
21
+ from wappa.messaging.whatsapp.models.interactive_models import (
22
+ ButtonMessage,
23
+ CTAMessage,
24
+ ListMessage,
25
+ )
26
+
27
+ # Create router with WhatsApp Interactive configuration
28
+ router = APIRouter(
29
+ prefix="/whatsapp/interactive",
30
+ tags=["WhatsApp - Interactive"],
31
+ responses={
32
+ 400: {"description": "Bad Request - Invalid interactive message format"},
33
+ 401: {"description": "Unauthorized - Invalid tenant credentials"},
34
+ 404: {"description": "Not Found - Recipient or resource not found"},
35
+ 413: {"description": "Payload Too Large - Interactive content too large"},
36
+ 429: {"description": "Rate Limited - Too many requests"},
37
+ 500: {"description": "Internal Server Error"},
38
+ },
39
+ )
40
+
41
+
42
+ @router.post(
43
+ "/send-buttons",
44
+ response_model=MessageResult,
45
+ summary="Send Button Message",
46
+ description="Send an interactive button message with up to 3 quick reply buttons",
47
+ )
48
+ async def send_button_message(
49
+ request: ButtonMessage, messenger: IMessenger = Depends(get_whatsapp_messenger)
50
+ ) -> MessageResult:
51
+ """Send interactive button message via WhatsApp.
52
+
53
+ Supports up to 3 quick reply buttons with optional header and footer.
54
+ Based on WhatsApp Cloud API 2025 interactive button specifications.
55
+ """
56
+ try:
57
+ # Convert Pydantic model to dict format expected by messenger
58
+ buttons = [{"id": btn.id, "title": btn.title} for btn in request.buttons]
59
+
60
+ header_dict = None
61
+ if request.header:
62
+ # Convert InteractiveHeader to dict format
63
+ header_dict = {"type": request.header.type.value}
64
+ if request.header.type.value == "text" and request.header.text:
65
+ header_dict["text"] = request.header.text
66
+ elif request.header.type.value == "image" and request.header.image:
67
+ header_dict["image"] = request.header.image
68
+ elif request.header.type.value == "video" and request.header.video:
69
+ header_dict["video"] = request.header.video
70
+ elif request.header.type.value == "document" and request.header.document:
71
+ header_dict["document"] = request.header.document
72
+
73
+ result = await messenger.send_button_message(
74
+ buttons=buttons,
75
+ recipient=request.recipient,
76
+ body=request.body,
77
+ header=header_dict,
78
+ footer=request.footer,
79
+ reply_to_message_id=request.reply_to_message_id,
80
+ )
81
+
82
+ if not result.success:
83
+ # Map specific error codes to HTTP status codes
84
+ if result.error_code in [
85
+ "BODY_TOO_LONG",
86
+ "FOOTER_TOO_LONG",
87
+ "BUTTON_TITLE_TOO_LONG",
88
+ "BUTTON_ID_TOO_LONG",
89
+ ]:
90
+ raise HTTPException(status_code=413, detail=result.error)
91
+ elif result.error_code in [
92
+ "INVALID_HEADER_TYPE",
93
+ "INVALID_TEXT_HEADER",
94
+ "INVALID_MEDIA_HEADER",
95
+ ]:
96
+ raise HTTPException(status_code=400, detail=result.error)
97
+ else:
98
+ raise HTTPException(status_code=400, detail=result.error)
99
+
100
+ return result
101
+
102
+ except HTTPException:
103
+ raise
104
+ except Exception as e:
105
+ raise HTTPException(
106
+ status_code=500, detail=f"Failed to send button message: {str(e)}"
107
+ )
108
+
109
+
110
+ @router.post(
111
+ "/send-list",
112
+ response_model=MessageResult,
113
+ summary="Send List Message",
114
+ description="Send an interactive list message with sectioned rows",
115
+ )
116
+ async def send_list_message(
117
+ request: ListMessage, messenger: IMessenger = Depends(get_whatsapp_messenger)
118
+ ) -> MessageResult:
119
+ """Send interactive list message via WhatsApp.
120
+
121
+ Supports sectioned lists with up to 10 sections and 10 rows per section.
122
+ Based on WhatsApp Cloud API 2025 interactive list specifications.
123
+ """
124
+ try:
125
+ # Convert Pydantic model to dict format expected by messenger
126
+ sections = []
127
+ for section in request.sections:
128
+ section_dict = {"title": section.title, "rows": []}
129
+ for row in section.rows:
130
+ row_dict = {"id": row.id, "title": row.title}
131
+ if row.description:
132
+ row_dict["description"] = row.description
133
+ section_dict["rows"].append(row_dict)
134
+ sections.append(section_dict)
135
+
136
+ result = await messenger.send_list_message(
137
+ sections=sections,
138
+ recipient=request.recipient,
139
+ body=request.body,
140
+ button_text=request.button_text,
141
+ header=request.header,
142
+ footer=request.footer,
143
+ reply_to_message_id=request.reply_to_message_id,
144
+ )
145
+
146
+ if not result.success:
147
+ # Map specific error codes to HTTP status codes
148
+ if result.error_code in [
149
+ "BODY_TOO_LONG",
150
+ "BUTTON_TEXT_TOO_LONG",
151
+ "HEADER_TOO_LONG",
152
+ "FOOTER_TOO_LONG",
153
+ ]:
154
+ raise HTTPException(status_code=413, detail=result.error)
155
+ elif result.error_code in [
156
+ "TOO_MANY_SECTIONS",
157
+ "TOO_MANY_ROWS",
158
+ "SECTION_TITLE_TOO_LONG",
159
+ "ROW_TITLE_TOO_LONG",
160
+ ] or result.error_code in [
161
+ "ROW_ID_TOO_LONG",
162
+ "ROW_DESCRIPTION_TOO_LONG",
163
+ "DUPLICATE_ROW_ID",
164
+ ]:
165
+ raise HTTPException(status_code=400, detail=result.error)
166
+ else:
167
+ raise HTTPException(status_code=400, detail=result.error)
168
+
169
+ return result
170
+
171
+ except HTTPException:
172
+ raise
173
+ except Exception as e:
174
+ raise HTTPException(
175
+ status_code=500, detail=f"Failed to send list message: {str(e)}"
176
+ )
177
+
178
+
179
+ @router.post(
180
+ "/send-cta",
181
+ response_model=MessageResult,
182
+ summary="Send Call-to-Action Message",
183
+ description="Send an interactive call-to-action message with URL button",
184
+ )
185
+ async def send_cta_message(
186
+ request: CTAMessage, messenger: IMessenger = Depends(get_whatsapp_messenger)
187
+ ) -> MessageResult:
188
+ """Send interactive call-to-action message via WhatsApp.
189
+
190
+ Supports external URL buttons for call-to-action scenarios.
191
+ Based on WhatsApp Cloud API 2025 CTA URL specifications.
192
+ """
193
+ try:
194
+ result = await messenger.send_cta_message(
195
+ button_text=request.button_text,
196
+ button_url=request.button_url,
197
+ recipient=request.recipient,
198
+ body=request.body,
199
+ header=request.header,
200
+ footer=request.footer,
201
+ reply_to_message_id=request.reply_to_message_id,
202
+ )
203
+
204
+ if not result.success:
205
+ # Map specific error codes to HTTP status codes
206
+ if (
207
+ result.error_code == "MISSING_REQUIRED_PARAMS"
208
+ or result.error_code == "INVALID_URL_FORMAT"
209
+ ):
210
+ raise HTTPException(status_code=400, detail=result.error)
211
+ else:
212
+ raise HTTPException(status_code=400, detail=result.error)
213
+
214
+ return result
215
+
216
+ except HTTPException:
217
+ raise
218
+ except Exception as e:
219
+ raise HTTPException(
220
+ status_code=500, detail=f"Failed to send CTA message: {str(e)}"
221
+ )
222
+
223
+
224
+ @router.get(
225
+ "/limits",
226
+ summary="Get Interactive Message Limits",
227
+ description="Get platform-specific interactive message limits and constraints",
228
+ )
229
+ async def get_interactive_limits() -> dict:
230
+ """Get WhatsApp interactive message limits and constraints.
231
+
232
+ Returns supported interactive types, size limits, and platform constraints.
233
+ """
234
+ return {
235
+ "button_messages": {
236
+ "max_buttons": 3,
237
+ "max_button_title_length": 20,
238
+ "max_button_id_length": 256,
239
+ "max_body_length": 1024,
240
+ "max_footer_length": 60,
241
+ "supported_header_types": ["text", "image", "video", "document"],
242
+ },
243
+ "list_messages": {
244
+ "max_sections": 10,
245
+ "max_rows_per_section": 10,
246
+ "max_button_text_length": 20,
247
+ "max_body_length": 4096,
248
+ "max_header_length": 60,
249
+ "max_footer_length": 60,
250
+ "max_section_title_length": 24,
251
+ "max_row_title_length": 24,
252
+ "max_row_description_length": 72,
253
+ "max_row_id_length": 200,
254
+ },
255
+ "cta_messages": {
256
+ "required_url_protocols": ["http://", "https://"],
257
+ "max_body_length": 4096,
258
+ "max_button_text_length": 256,
259
+ "max_header_length": 60,
260
+ "max_footer_length": 60,
261
+ },
262
+ "general": {
263
+ "supported_platforms": ["whatsapp"],
264
+ "requires_authentication": True,
265
+ "rate_limits": "Per WhatsApp Business API terms",
266
+ },
267
+ }
268
+
269
+
270
+ @router.get(
271
+ "/health",
272
+ summary="Interactive Service Health Check",
273
+ description="Check health status of interactive messaging services",
274
+ )
275
+ async def health_check(messenger: IMessenger = Depends(get_whatsapp_messenger)) -> dict:
276
+ """Health check for interactive messaging services.
277
+
278
+ Returns service status and configuration information.
279
+ """
280
+ return {
281
+ "status": "healthy",
282
+ "service": "whatsapp-interactive",
283
+ "platform": messenger.platform.value,
284
+ "tenant_id": messenger.tenant_id,
285
+ "interactive_types": ["button", "list", "cta_url"],
286
+ "message_types_supported": [
287
+ "text",
288
+ "image",
289
+ "video",
290
+ "audio",
291
+ "document",
292
+ "sticker",
293
+ "button",
294
+ "list",
295
+ "cta_url",
296
+ ],
297
+ }
298
+
299
+
300
+ # Example endpoint demonstrating complex interactive message construction
301
+ @router.post(
302
+ "/send-complex-buttons",
303
+ response_model=MessageResult,
304
+ summary="Send Complex Button Message (Example)",
305
+ description="Example endpoint showing complex button message with all features",
306
+ )
307
+ async def send_complex_button_message(
308
+ recipient: str, messenger: IMessenger = Depends(get_whatsapp_messenger)
309
+ ) -> MessageResult:
310
+ """Example endpoint demonstrating complex button message construction.
311
+
312
+ This endpoint shows how to create a button message with header, footer,
313
+ and multiple buttons programmatically.
314
+ """
315
+ try:
316
+ # Example complex button message
317
+ buttons = [
318
+ {"id": "yes_button", "title": "✅ Yes"},
319
+ {"id": "no_button", "title": "❌ No"},
320
+ {"id": "maybe_button", "title": "🤔 Maybe"},
321
+ ]
322
+
323
+ header = {"type": "text", "text": "Quick Decision Required"}
324
+
325
+ result = await messenger.send_button_message(
326
+ buttons=buttons,
327
+ recipient=recipient,
328
+ body="Would you like to proceed with this action? Please choose one of the options below.",
329
+ header=header,
330
+ footer="This message will expire in 24 hours",
331
+ )
332
+
333
+ if not result.success:
334
+ raise HTTPException(status_code=400, detail=result.error)
335
+
336
+ return result
337
+
338
+ except HTTPException:
339
+ raise
340
+ except Exception as e:
341
+ raise HTTPException(
342
+ status_code=500, detail=f"Failed to send complex button message: {str(e)}"
343
+ )
344
+
345
+
346
+ # Example endpoint for list messages
347
+ @router.post(
348
+ "/send-menu-list",
349
+ response_model=MessageResult,
350
+ summary="Send Menu List Message (Example)",
351
+ description="Example endpoint showing menu-style list message",
352
+ )
353
+ async def send_menu_list_message(
354
+ recipient: str, messenger: IMessenger = Depends(get_whatsapp_messenger)
355
+ ) -> MessageResult:
356
+ """Example endpoint demonstrating menu-style list message construction.
357
+
358
+ This endpoint shows how to create a restaurant menu using list messages.
359
+ """
360
+ try:
361
+ # Example menu list message
362
+ sections = [
363
+ {
364
+ "title": "🍕 Main Dishes",
365
+ "rows": [
366
+ {
367
+ "id": "pizza_margherita",
368
+ "title": "Pizza Margherita",
369
+ "description": "Classic tomato and mozzarella - $12.99",
370
+ },
371
+ {
372
+ "id": "pasta_carbonara",
373
+ "title": "Pasta Carbonara",
374
+ "description": "Creamy bacon pasta - $14.99",
375
+ },
376
+ ],
377
+ },
378
+ {
379
+ "title": "🥗 Salads",
380
+ "rows": [
381
+ {
382
+ "id": "caesar_salad",
383
+ "title": "Caesar Salad",
384
+ "description": "Crispy romaine with parmesan - $8.99",
385
+ },
386
+ {
387
+ "id": "greek_salad",
388
+ "title": "Greek Salad",
389
+ "description": "Fresh vegetables with feta - $9.99",
390
+ },
391
+ ],
392
+ },
393
+ {
394
+ "title": "🥤 Beverages",
395
+ "rows": [
396
+ {
397
+ "id": "coke",
398
+ "title": "Coca Cola",
399
+ "description": "Classic refreshing cola - $2.99",
400
+ },
401
+ {
402
+ "id": "water",
403
+ "title": "Sparkling Water",
404
+ "description": "Refreshing mineral water - $1.99",
405
+ },
406
+ ],
407
+ },
408
+ ]
409
+
410
+ result = await messenger.send_list_message(
411
+ sections=sections,
412
+ recipient=recipient,
413
+ body="Welcome to our restaurant! Browse our menu and select what you'd like to order.",
414
+ button_text="View Menu",
415
+ header="🍽️ Restaurant Menu",
416
+ footer="Prices include tax • Free delivery over $25",
417
+ )
418
+
419
+ if not result.success:
420
+ raise HTTPException(status_code=400, detail=result.error)
421
+
422
+ return result
423
+
424
+ except HTTPException:
425
+ raise
426
+ except Exception as e:
427
+ raise HTTPException(
428
+ status_code=500, detail=f"Failed to send menu list message: {str(e)}"
429
+ )