FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Enviar mensajes por whatsapp?
Posts: 3382
Joined: Fri Oct 07, 2005 08:20 PM

Enviar mensajes por whatsapp?

Posted: Wed May 06, 2026 04:05 AM

Amigos foreros:

Necesito una clase para enviar mensajes por whatsapp, he buscado en el foro y parece que lo que hay aún no están totalmente maduras, me equivoco?

Alguna clase recomendada?

Saludos

SOI, s.a. de c.v.
estbucarm@gmail.com
http://www.soisa.mex.tl/
http://sqlcmd.blogspot.com/
Tel. (722) 174 44 45
Carpe diem quam minimum credula postero
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Enviar mensajes por whatsapp?

Posted: Wed May 06, 2026 04:18 AM

No equivocas. Foro samples (whatsapp.prg, whatsappw.prg) usan truco whatsapp:// + clipboard + SendKeys. Frágil:
requiere app desktop abierta, depende timing y foco ventana. No API real.

Tres caminos serios:

  1. WhatsApp Cloud API (Meta oficial) — REST HTTPS, gratis hasta cierto volumen. Requiere registrar número business +
    token. Mensajes plantilla aprobados para iniciar conversación. Maduro, soportado.

  2. Twilio / 360dialog / wati — gateways pagos sobre Cloud API. Más simple integrar, coste por mensaje.

  3. whatsapp-web.js / Baileys (no oficial, Node.js) — automatiza WhatsApp Web por websocket. Riesgo ban cuenta, no
    recomendable producción.

    Recomendación: clase TWhatsApp envolviendo Cloud API con WinHttp.WinHttpRequest.5.1 o hb_curl. Maduro, oficial, sin
    dependencia de app desktop. Tradeoff: necesitas Meta Business Account + número verificado + plantillas aprobadas para
    mensajes salientes a usuarios que no escribieron primero.

    Quieres prototipo TWhatsApp Cloud API? (construyendola...)

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Enviar mensajes por whatsapp?

Posted: Wed May 06, 2026 04:26 AM
// WhatsApp Cloud API client (Meta Business)
// Requires: Meta Business Account, App, registered phone number ID, permanent access token.
// Docs: https://developers.facebook.com/docs/whatsapp/cloud-api

#include "FiveWin.ch"
#include "hbcurl.ch"

//----------------------------------------------------------------------------//

CLASS TWhatsApp

   DATA   cToken                          // Bearer access token
   DATA   cPhoneId                        // sender phone number ID (Meta numeric ID, not the phone)
   DATA   cVersion    INIT "v18.0"        // Graph API version
   DATA   cBaseUrl    INIT "https://graph.facebook.com"
   DATA   hCurl
   DATA   cResponse
   DATA   nError      INIT 0
   DATA   nHttpCode   INIT 0

   METHOD New( cToken, cPhoneId, cVersion ) CONSTRUCTOR
   METHOD End()

   METHOD SendText( cTo, cMsg, lPreviewUrl )
   METHOD SendTemplate( cTo, cName, cLang, aBodyParams )
   METHOD SendImage( cTo, cLinkOrId, cCaption )
   METHOD SendDocument( cTo, cLinkOrId, cFilename, cCaption )
   METHOD SendAudio( cTo, cLinkOrId )
   METHOD SendVideo( cTo, cLinkOrId, cCaption )
   METHOD SendLocation( cTo, nLat, nLong, cName, cAddress )

   METHOD UploadMedia( cFileName, cMimeType )   // returns media id or nil
   METHOD DownloadMedia( cMediaId, cTargetFile )

   METHOD Post( cUrl, cJson )
   METHOD MessagesUrl()  INLINE ::cBaseUrl + "/" + ::cVersion + "/" + ::cPhoneId + "/messages"
   METHOD MediaUrl()     INLINE ::cBaseUrl + "/" + ::cVersion + "/" + ::cPhoneId + "/media"

   METHOD GetError()
   METHOD GetMessageId()

ENDCLASS

//----------------------------------------------------------------------------//

METHOD New( cToken, cPhoneId, cVersion ) CLASS TWhatsApp

   ::cToken   := cToken
   ::cPhoneId := cPhoneId
   if ! Empty( cVersion )
      ::cVersion := cVersion
   endif
   ::hCurl := curl_easy_init()

return Self

//----------------------------------------------------------------------------//

METHOD End() CLASS TWhatsApp

   if ::hCurl != nil
      curl_easy_cleanup( ::hCurl )
      ::hCurl := nil
   endif

return nil

//----------------------------------------------------------------------------//

METHOD Post( cUrl, cJson ) CLASS TWhatsApp

   local aHeaders

   curl_easy_reset( ::hCurl )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, cUrl )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, .T. )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .T. )

   aHeaders := { "Authorization: Bearer " + ::cToken, ;
                 "Content-Type: application/json" }
   curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, aHeaders )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_POSTFIELDS, cJson )

   ::nError = curl_easy_perform( ::hCurl )
   curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @::nHttpCode )

   if ::nError == HB_CURLE_OK
      ::cResponse := curl_easy_dl_buff_get( ::hCurl )
   else
      ::cResponse := '{"error":{"message":"curl error ' + LTrim( Str( ::nError ) ) + '"}}'
   endif

return ::cResponse

//----------------------------------------------------------------------------//

METHOD SendText( cTo, cMsg, lPreviewUrl ) CLASS TWhatsApp

   local hReq := { => }, hText := { => }

   DEFAULT lPreviewUrl := .F.

   hReq[ "messaging_product" ] := "whatsapp"
   hReq[ "recipient_type" ]    := "individual"
   hReq[ "to" ]                := cTo
   hReq[ "type" ]              := "text"
   hText[ "preview_url" ]      := lPreviewUrl
   hText[ "body" ]             := cMsg
   hReq[ "text" ]              := hText

return ::Post( ::MessagesUrl(), hb_jsonEncode( hReq ) )

//----------------------------------------------------------------------------//

METHOD SendTemplate( cTo, cName, cLang, aBodyParams ) CLASS TWhatsApp

   local hReq := { => }, hTpl := { => }, hLang := { => }
   local aComponents, hComp, aParams, n

   DEFAULT cLang := "en_US"

   hReq[ "messaging_product" ] := "whatsapp"
   hReq[ "to" ]                := cTo
   hReq[ "type" ]              := "template"

   hLang[ "code" ] := cLang
   hTpl[ "name" ]     := cName
   hTpl[ "language" ] := hLang

   if HB_ISARRAY( aBodyParams ) .and. Len( aBodyParams ) > 0
      aParams := {}
      for n := 1 to Len( aBodyParams )
         AAdd( aParams, { "type" => "text", "text" => aBodyParams[ n ] } )
      next
      hComp := { "type" => "body", "parameters" => aParams }
      aComponents := { hComp }
      hTpl[ "components" ] := aComponents
   endif

   hReq[ "template" ] := hTpl

return ::Post( ::MessagesUrl(), hb_jsonEncode( hReq ) )

//----------------------------------------------------------------------------//

METHOD SendImage( cTo, cLinkOrId, cCaption ) CLASS TWhatsApp

   local hReq := { => }, hImg := { => }

   hReq[ "messaging_product" ] := "whatsapp"
   hReq[ "to" ]                := cTo
   hReq[ "type" ]              := "image"

   if Left( Lower( cLinkOrId ), 4 ) == "http"
      hImg[ "link" ] := cLinkOrId
   else
      hImg[ "id" ] := cLinkOrId
   endif
   if ! Empty( cCaption )
      hImg[ "caption" ] := cCaption
   endif
   hReq[ "image" ] := hImg

return ::Post( ::MessagesUrl(), hb_jsonEncode( hReq ) )

//----------------------------------------------------------------------------//

METHOD SendDocument( cTo, cLinkOrId, cFilename, cCaption ) CLASS TWhatsApp

   local hReq := { => }, hDoc := { => }

   hReq[ "messaging_product" ] := "whatsapp"
   hReq[ "to" ]                := cTo
   hReq[ "type" ]              := "document"

   if Left( Lower( cLinkOrId ), 4 ) == "http"
      hDoc[ "link" ] := cLinkOrId
   else
      hDoc[ "id" ] := cLinkOrId
   endif
   if ! Empty( cFilename )
      hDoc[ "filename" ] := cFilename
   endif
   if ! Empty( cCaption )
      hDoc[ "caption" ] := cCaption
   endif
   hReq[ "document" ] := hDoc

return ::Post( ::MessagesUrl(), hb_jsonEncode( hReq ) )

//----------------------------------------------------------------------------//

METHOD SendAudio( cTo, cLinkOrId ) CLASS TWhatsApp

   local hReq := { => }, hAudio := { => }

   hReq[ "messaging_product" ] := "whatsapp"
   hReq[ "to" ]                := cTo
   hReq[ "type" ]              := "audio"

   if Left( Lower( cLinkOrId ), 4 ) == "http"
      hAudio[ "link" ] := cLinkOrId
   else
      hAudio[ "id" ] := cLinkOrId
   endif
   hReq[ "audio" ] := hAudio

return ::Post( ::MessagesUrl(), hb_jsonEncode( hReq ) )

//----------------------------------------------------------------------------//

METHOD SendVideo( cTo, cLinkOrId, cCaption ) CLASS TWhatsApp

   local hReq := { => }, hVideo := { => }

   hReq[ "messaging_product" ] := "whatsapp"
   hReq[ "to" ]                := cTo
   hReq[ "type" ]              := "video"

   if Left( Lower( cLinkOrId ), 4 ) == "http"
      hVideo[ "link" ] := cLinkOrId
   else
      hVideo[ "id" ] := cLinkOrId
   endif
   if ! Empty( cCaption )
      hVideo[ "caption" ] := cCaption
   endif
   hReq[ "video" ] := hVideo

return ::Post( ::MessagesUrl(), hb_jsonEncode( hReq ) )

//----------------------------------------------------------------------------//

METHOD SendLocation( cTo, nLat, nLong, cName, cAddress ) CLASS TWhatsApp

   local hReq := { => }, hLoc := { => }

   hReq[ "messaging_product" ] := "whatsapp"
   hReq[ "to" ]                := cTo
   hReq[ "type" ]              := "location"

   hLoc[ "latitude" ]  := nLat
   hLoc[ "longitude" ] := nLong
   if ! Empty( cName )
      hLoc[ "name" ] := cName
   endif
   if ! Empty( cAddress )
      hLoc[ "address" ] := cAddress
   endif
   hReq[ "location" ] := hLoc

return ::Post( ::MessagesUrl(), hb_jsonEncode( hReq ) )

//----------------------------------------------------------------------------//

METHOD UploadMedia( cFileName, cMimeType ) CLASS TWhatsApp

   local aHeaders, hResp, cMediaId

   if ! File( cFileName )
      ::cResponse := '{"error":{"message":"file not found"}}'
      return nil
   endif

   DEFAULT cMimeType := "application/octet-stream"

   curl_easy_reset( ::hCurl )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::MediaUrl() )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .T. )

   aHeaders := { "Authorization: Bearer " + ::cToken }
   curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, aHeaders )

   curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPPOST, { ;
      { "name" => "messaging_product", "contents" => "whatsapp" }, ;
      { "name" => "type",              "contents" => cMimeType }, ;
      { "name" => "file",              "file" => cFileName, "type" => cMimeType } } )

   ::nError = curl_easy_perform( ::hCurl )
   curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @::nHttpCode )

   if ::nError == HB_CURLE_OK
      ::cResponse := curl_easy_dl_buff_get( ::hCurl )
      hb_jsonDecode( ::cResponse, @hResp )
      if HB_ISHASH( hResp ) .and. hb_HHasKey( hResp, "id" )
         cMediaId := hResp[ "id" ]
      endif
   else
      ::cResponse := '{"error":{"message":"curl error ' + LTrim( Str( ::nError ) ) + '"}}'
   endif

return cMediaId

//----------------------------------------------------------------------------//

METHOD DownloadMedia( cMediaId, cTargetFile ) CLASS TWhatsApp

   local aHeaders, hResp, cUrl, cBin, hFile

   curl_easy_reset( ::hCurl )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::cBaseUrl + "/" + ::cVersion + "/" + cMediaId )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .T. )
   aHeaders := { "Authorization: Bearer " + ::cToken }
   curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, aHeaders )
   ::nError := curl_easy_perform( ::hCurl )
   if ::nError != HB_CURLE_OK
      return .F.
   endif
   ::cResponse := curl_easy_dl_buff_get( ::hCurl )
   hb_jsonDecode( ::cResponse, @hResp )
   if ! HB_ISHASH( hResp ) .or. ! hb_HHasKey( hResp, "url" )
      return .F.
   endif
   cUrl := hResp[ "url" ]

   curl_easy_reset( ::hCurl )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, cUrl )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .T. )
   curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPHEADER, { "Authorization: Bearer " + ::cToken } )
   ::nError := curl_easy_perform( ::hCurl )
   if ::nError != HB_CURLE_OK
      return .F.
   endif
   cBin := curl_easy_dl_buff_get( ::hCurl )

   hFile := FCreate( cTargetFile )
   if FError() != 0
      return .F.
   endif
   FWrite( hFile, cBin )
   FClose( hFile )

return .T.

//----------------------------------------------------------------------------//

METHOD GetError() CLASS TWhatsApp

   local hResp, cMsg := ""

   if Empty( ::cResponse )
      return ""
   endif
   hb_jsonDecode( ::cResponse, @hResp )
   if HB_ISHASH( hResp ) .and. hb_HHasKey( hResp, "error" )
      if HB_ISHASH( hResp[ "error" ] ) .and. hb_HHasKey( hResp[ "error" ], "message" )
         cMsg := hResp[ "error" ][ "message" ]
      endif
   endif

return cMsg

//----------------------------------------------------------------------------//

METHOD GetMessageId() CLASS TWhatsApp

   local hResp, cId := ""

   if Empty( ::cResponse )
      return ""
   endif
   hb_jsonDecode( ::cResponse, @hResp )
   if HB_ISHASH( hResp ) .and. hb_HHasKey( hResp, "messages" )
      if HB_ISARRAY( hResp[ "messages" ] ) .and. Len( hResp[ "messages" ] ) > 0
         if hb_HHasKey( hResp[ "messages" ][ 1 ], "id" )
            cId := hResp[ "messages" ][ 1 ][ "id" ]
         endif
      endif
   endif

return cId

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Enviar mensajes por whatsapp?

Posted: Wed May 06, 2026 04:28 AM

Pregunta: ¿es gratuito?

Cloud API tiene tier gratis pero limitado. Modelo Meta cambió 2025-07-01:

Free tier:

  • 1.000 conversaciones/mes con service messages (responder dentro de ventana 24h tras mensaje del usuario). Gratis.

  • Marketing/utility/authentication templates: NO gratis. Pago por mensaje según país.

    Tarifas template (España, ejemplo):

  • Marketing: 0,0691 €/msg

  • Utility: 0,0287 €/msg (gratis si dentro ventana servicio 24h desde 2025-11)

  • Authentication: 0,0287 €/msg

    Otros países más baratos (India 0,008€, México 0,02€). Tarifa exacta:
    https://developers.facebook.com/docs/whatsapp/pricing

    Costes infra: cero. Sin cuota mensual Meta. Solo pagas mensajes salientes iniciados por business.

    Recibir mensajes: siempre gratis.

    Resumen: desarrollo + pruebas con números allowlist = gratis. Producción: gratis para responder usuarios (24h
    ventana), pago por iniciar conversación con templates.

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Enviar mensajes por whatsapp?

Posted: Wed May 06, 2026 04:30 AM

como hago para probarla ?

● Pasos para probar (orden importa):

  1. Crear app Meta

  2. https://developers.facebook.com/apps → "Create App" → tipo "Business"

  3. Add product → WhatsApp → "Set up"

  4. Obtener credenciales

    En panel WhatsApp → "API Setup":

  5. Temporary access token (24h, suficiente para probar) — cópialo

  6. Phone number ID del número de prueba que Meta da gratis — cópialo

  7. Token permanente luego: Business Settings → System Users → genera token con permiso whatsapp_business_messaging +
    whatsapp_business_management

  8. Registrar tu móvil como destino test

    En "API Setup" → sección "To" → "Manage phone number list" → añade tu móvil con código país (ej. +34666...). Meta
    envía SMS con código verificación.

  9. Editar sample

    c:\fwteam\samples\misc\twhatsapp.prg líneas 18-20:
    static cToken := "EAAxxxxxxxxxxxxxxxx" // pega token aquí
    static cPhoneId := "123456789012345" // pega phone number ID
    static cTo := "34666555444" // tu móvil verificado, sin +

  10. Compilar

    cd /d C:\fwteam\samples\misc
    C:\fwteam\samples\build_new.bat twhatsapp hb64

    (o variante: hb32, hm64, hg64, etc.)

  11. Ejecutar

    build_new.bat lanza exe automático. Pulsa botón "Template" primero — único que funciona sin que destinatario te haya
    escrito antes (template hello_world viene preaprobado por Meta).

  12. Verificar

  13. Tu móvil recibe mensaje "Hello World" en WhatsApp

  14. MsgInfo muestra HTTP 200 + id: wamid.xxxxx

  15. Si falla: ver error: en MsgInfo (token caducado, número no en allowlist, etc.)

  16. Después de hello_world

    Una vez tu móvil responde algo al business, ventana 24h abierta → botones Text/Image/Document/Location funcionan
    (mensajes sesión, gratis).

    Errores comunes:

  17. (#131030) Recipient phone number not in allowed list → falta verificar móvil en allowlist

  18. (#190) Access token expired → regenera token (temporal dura 24h)

  19. (#132001) Template name does not exist → template no aprobado en tu idioma

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Enviar mensajes por whatsapp?

Posted: Wed May 06, 2026 04:32 AM
// Sample for TWhatsApp class — WhatsApp Cloud API (Meta Business)
//
// Setup steps (one-time):
//   1. Create Meta Business Account: https://business.facebook.com/
//   2. Create app at https://developers.facebook.com/apps/ (type: Business)
//   3. Add WhatsApp product, register a phone number, get PHONE_NUMBER_ID
//   4. Generate permanent access token (System User)
//   5. Add destination phone numbers to "Allowed list" (sandbox) or
//      get number out of sandbox by submitting business verification
//   6. For unsolicited messages create and approve a message template

#include "FiveWin.ch"

#define CRLF Chr(13)+Chr(10)

static cToken   := "EAAxxxxxxxxxxxxxxxx"      // Bearer token
static cPhoneId := "123456789012345"          // sender phone number ID
static cTo      := "34666555444"              // recipient (E.164 without +)

//----------------------------------------------------------------------------//

function Main()

   local oWnd, oWa

   oWa := TWhatsApp():New( cToken, cPhoneId )

   DEFINE WINDOW oWnd TITLE "TWhatsApp test"

   ACTIVATE WINDOW oWnd ON INIT BuildMenu( oWnd, oWa ) ;
                       VALID ( oWa:End(), .T. )

return nil

//----------------------------------------------------------------------------//

static function BuildMenu( oWnd, oWa )

   local oBar

   DEFINE BUTTONBAR oBar OF oWnd SIZE 60, 60 2007

   DEFINE BUTTON OF oBar PROMPT "Text"        ACTION TestText( oWa )
   DEFINE BUTTON OF oBar PROMPT "Template"    ACTION TestTemplate( oWa )
   DEFINE BUTTON OF oBar PROMPT "Image URL"   ACTION TestImageUrl( oWa )
   DEFINE BUTTON OF oBar PROMPT "Upload+Img"  ACTION TestUploadImage( oWa )
   DEFINE BUTTON OF oBar PROMPT "Document"    ACTION TestDocument( oWa )
   DEFINE BUTTON OF oBar PROMPT "Location"    ACTION TestLocation( oWa )

return nil

//----------------------------------------------------------------------------//

static function TestText( oWa )

   oWa:SendText( cTo, "Hello from FiveWin via Cloud API " + Time() )
   ShowResult( oWa )

return nil

//----------------------------------------------------------------------------//

static function TestTemplate( oWa )

   // hello_world is the default template enabled on every new app
   oWa:SendTemplate( cTo, "hello_world", "en_US" )
   ShowResult( oWa )

return nil

//----------------------------------------------------------------------------//

static function TestImageUrl( oWa )

   oWa:SendImage( cTo, ;
      "https://www.fivetechsoft.com/images/fivewin_logo.png", ;
      "FiveWin logo" )
   ShowResult( oWa )

return nil

//----------------------------------------------------------------------------//

static function TestUploadImage( oWa )

   local cFile := "..\bitmaps\007.bmp"
   local cId

   if ! File( cFile )
      MsgAlert( "File not found: " + cFile )
      return nil
   endif

   cId := oWa:UploadMedia( cFile, "image/bmp" )
   if Empty( cId )
      MsgAlert( oWa:GetError(), "Upload failed" )
      return nil
   endif
   oWa:SendImage( cTo, cId, "uploaded local file" )
   ShowResult( oWa )

return nil

//----------------------------------------------------------------------------//

static function TestDocument( oWa )

   oWa:SendDocument( cTo, ;
      "https://www.fivetechsoft.com/files/fwh_releases.pdf", ;
      "release_notes.pdf", "FWH release notes" )
   ShowResult( oWa )

return nil

//----------------------------------------------------------------------------//

static function TestLocation( oWa )

   oWa:SendLocation( cTo, 36.5108, -6.2693, "FiveTech HQ", "Cadiz, Spain" )
   ShowResult( oWa )

return nil

//----------------------------------------------------------------------------//

static function ShowResult( oWa )

   local cInfo

   cInfo := "HTTP " + LTrim( Str( oWa:nHttpCode ) ) + CRLF + ;
           "id: " + oWa:GetMessageId() + CRLF + ;
           "error: " + oWa:GetError() + CRLF + CRLF + ;
           "raw: " + oWa:cResponse

   MsgInfo( cInfo, "WhatsApp" )

return nil

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Enviar mensajes por whatsapp?

Posted: Wed May 06, 2026 04:33 AM

Añadido al próximo build de FWH

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Enviar mensajes por whatsapp?

Posted: Wed May 06, 2026 04:34 AM

Esto son claros ejemplos de la importancia de usar Claude Code :wink:

Invitaciones gratuitas para probar Claude Code:
https://claude.ai/referral/9MBf7GAUAQ

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 3382
Joined: Fri Oct 07, 2005 08:20 PM

Re: Enviar mensajes por whatsapp?

Posted: Thu May 07, 2026 02:36 AM

Maestro Linares:

Gracias por las respuestas.

Debí comentar que mi necesidad es para una aplicación que me solicita un médico y la idea es enviar mensajes por whatsapp cuando se haya registrado/pospuesto/cancelado alguna cita.

La cantidad de mensajes no será muy alto.

Saludos

SOI, s.a. de c.v.
estbucarm@gmail.com
http://www.soisa.mex.tl/
http://sqlcmd.blogspot.com/
Tel. (722) 174 44 45
Carpe diem quam minimum credula postero
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Enviar mensajes por whatsapp?

Posted: Thu May 07, 2026 02:42 AM

Perfecto encaje para Cloud API. Caso de uso ideal: utility templates (notificaciones transaccionales).

Por qué encaja bien:

  • Notificaciones de cita = categoría utility (no marketing). Tarifa más baja (0,0287€/msg España).

  • Desde nov 2025: utility messages gratis si paciente escribió al business en últimas 24h. Si no, pago por template.

  • Volumen bajo → cabe sobrado en límite gratuito (1.000 conversaciones/mes service).

  • Coste estimado consulta típica (300 citas/mes notificadas): 8,60€/mes worst case, mucho menos si pacientes
    confirman.

    Plantillas a aprobar (Meta):

    Crea 3 templates en Business Manager → WhatsApp Manager → Message Templates → Categoría: Utility:

    Nombre: cita_confirmada
    Idioma: es
    Body: Hola {{1}}, su cita con Dr. {{2}} queda confirmada para {{3}} a las {{4}}h.
    Responda CANCELAR para anularla.

    Nombre: cita_pospuesta
    Idioma: es
    Body: Hola {{1}}, su cita con Dr. {{2}} se ha movido del {{3}} al {{4}} a las {{5}}h.

    Nombre: cita_cancelada
    Idioma: es
    Body: Hola {{1}}, su cita del {{2}} con Dr. {{3}} ha sido cancelada.
    Para reagendar llame al {{4}}.

    Aprobación Meta: 1-24h normalmente. Plantilla utility se aprueba rápido si texto neutro/informativo.

    Uso en código:

    local oWa := TWhatsApp():New( cToken, cPhoneId )

    // confirmación
    oWa:SendTemplate( "34666555444", "cita_confirmada", "es", ;
    { "María García", "López", "lunes 12 mayo", "10:30" } )

    // pospuesta
    oWa:SendTemplate( "34666555444", "cita_pospuesta", "es", ;
    { "María García", "López", "12/05", "19/05", "10:30" } )

    // cancelada
    oWa:SendTemplate( "34666555444", "cita_cancelada", "es", ;
    { "María García", "12/05", "López", "956123456" } )

    Datos médicos / GDPR:

  • Meta Cloud API es procesador GDPR. Firma DPA en Business Settings.

  • Mensaje WhatsApp NO es canal médico seguro oficial. Mejor solo: nombre, fecha, hora, médico. Nunca diagnóstico,
    medicación, resultados.

  • Consentimiento explícito del paciente para notificaciones WhatsApp (firmar al alta).

    Webhook entrante (opcional pero útil):

    Si paciente responde "CANCELAR", recibes webhook. Necesitas endpoint HTTPS público. Para empezar puedes ignorarlo y
    usar solo salida.

    Stack mínimo para empezar:

  • App Meta + número test gratis → probar hello_world

  • Crear las 3 plantillas utility → esperar aprobación

  • Verificar negocio (Business Verification) → necesario para producción y para sacar número del sandbox

  • Comprar número WhatsApp Business (puedes usar línea fija/móvil propia, Meta hace verificación SMS/llamada)

  • Token permanente System User

  • Integrar TWhatsApp en módulo de citas: hook al guardar/posponer/cancelar registro → llama al template
    correspondiente

    Quieres que añada métodos helper tipo SendAppointment( cTo, cPatient, cDoctor, dDate, cTime, cAction ) que envuelva
    los 3 templates?

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Enviar mensajes por whatsapp?

Posted: Thu May 07, 2026 02:43 AM

Puedes usar la versión de prueba de Claude Code (enlace que he publicado) y decirle que te lo haga el todo :idea:

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 413
Joined: Sun Jan 31, 2010 03:30 PM

Re: Enviar mensajes por whatsapp?

Posted: Sun May 10, 2026 09:23 PM

Buena tarde...

Alguien ya hizo la validación y publicación de la APP como desarrollador meta o Facebook,
como uno de los requisitos para empezar a usar la API en producción ?

Compartamos ideas ...

Nota : 1 . Ya tengo interface con api meta usando un BSP - onurix, funcionando: ok

  1. Estoy medio varado en la publicación de la app con api meta directamente.

  2. CC me creo un server python, para multiples funciones: convertir informes legacy a tipo web, crear y enviar PDF via WhatsApp o email, api rest / websocket- SQL, etc..

  3. Todo usando fivewin + harbour

JONSSON RUSSI

Posts: 38
Joined: Tue Mar 20, 2012 11:06 PM

Re: Enviar mensajes por whatsapp?

Posted: Thu Jul 02, 2026 09:16 PM
Antonio Linares wrote:

Puedes usar la versión de prueba de Claude Code (enlace que he publicado) y decirle que te lo haga el todo :idea:

Hola Antonio, el enlace publicado no funciona mas.. tengo una cuenta plus en Code Chatgpt para divertirme un rato ya que hace rato que no programo pero siempre algo me gusta probar en harbour (Contexto: deje de programar en el 2018 tras la muerte de mi amigo como tambien deje de reparar equipos, soy tecnico electronico. ) todo eso despues de 30 años hoy mi trabajo actual es ser Piercer que en su tiempo era HOBBY.
gracias siempre los leo asi como otros foros harbour

Posts: 259
Joined: Mon Jun 10, 2013 06:40 PM

Re: Enviar mensajes por whatsapp?

Posted: Tue Jul 14, 2026 05:34 PM

https://textmebot.com/

Muy Fácil, solo que es de paga, pero muy económico.

Continue the discussion