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
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
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:
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.
Twilio / 360dialog / wati — gateways pagos sobre Cloud API. Más simple integrar, coste por mensaje.
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...)
Code: Select all | Expand
// 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
//----------------------------------------------------------------------------//
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.
como hago para probarla ?
● Pasos para probar (orden importa):
Crear app Meta
https://developers.facebook.com/apps → "Create App" → tipo "Business"
Add product → WhatsApp → "Set up"
Obtener credenciales
En panel WhatsApp → "API Setup":
Temporary access token (24h, suficiente para probar) — cópialo
Phone number ID del número de prueba que Meta da gratis — cópialo
Token permanente luego: Business Settings → System Users → genera token con permiso whatsapp_business_messaging +
whatsapp_business_management
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.
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 +
Compilar
cd /d C:\fwteam\samples\misc
C:\fwteam\samples\build_new.bat twhatsapp hb64
(o variante: hb32, hm64, hg64, etc.)
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).
Verificar
Tu móvil recibe mensaje "Hello World" en WhatsApp
MsgInfo muestra HTTP 200 + id: wamid.xxxxx
Si falla: ver error: en MsgInfo (token caducado, número no en allowlist, etc.)
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:
(#131030) Recipient phone number not in allowed list → falta verificar móvil en allowlist
(#190) Access token expired → regenera token (temporal dura 24h)
(#132001) Template name does not exist → template no aprobado en tu idioma
Code: Select all | Expand
// 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
//----------------------------------------------------------------------------//
Esto son claros ejemplos de la importancia de usar Claude Code ![]()
Invitaciones gratuitas para probar Claude Code:
https://claude.ai/referral/9MBf7GAUAQ
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
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?
Puedes usar la versión de prueba de Claude Code (enlace que he publicado) y decirle que te lo haga el todo ![]()
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
Estoy medio varado en la publicación de la app con api meta directamente.
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..
Todo usando fivewin + harbour
JONSSON RUSSI
Antonio Linares wrote: Thu May 07, 2026 2:43 amPuedes usar la versión de prueba de Claude Code (enlace que he publicado) y decirle que te lo haga el todo
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