Primeros pasos

Envía tu primer mensaje de WhatsApp

Objetivo

Envía un mensaje de texto de WhatsApp desde un programa en TypeScript con Bun y Kapso.

Esta es la prueba de integración más pequeña que resulta útil. Demuestra que tu proyecto de Kapso, el remitente de WhatsApp, la clave de API, el SDK y el destinatario de prueba pueden funcionar juntos antes de que agregues un servidor web o un modelo de IA.

Requisitos previos

  • Bun instalado
  • Una cuenta de Kapso
  • Un número de WhatsApp conectado o una sesión activa del sandbox de Kapso
  • Un destinatario de prueba que haya dado su consentimiento
  • Una ventana de atención al cliente de WhatsApp abierta o una plantilla aprobada

Comprueba el remitente en Kapso

Abre WhatsApp > Phone numbers en Kapso. Hay dos valores con nombres parecidos, pero cumplen funciones diferentes:

Valor Significado
Phone number El número visible de WhatsApp al que una persona envía mensajes
Phone Number ID El identificador técnico de Meta para el remitente empresarial

Envía un mensaje desde tu teléfono de prueba autorizado al número conectado y luego abre el Inbox de Kapso. Ver esa conversación confirma que el número está activo.

Si usas el sandbox, envía mensajes únicamente al teléfono registrado para la sesión activa del sandbox.

Crea el proyecto con Bun

bun init receptionist-ai
cd receptionist-ai
bun run index.ts
bun add @kapso/whatsapp-cloud-api

La primera ejecución muestra el mensaje inicial de Bun. Reemplaza ese código inicial después de instalar el SDK.

Mantén la configuración fuera del código fuente

Crea una clave de Kapso en Integrations > API keys. Agrega tus propios valores a .env:

KAPSO_API_KEY=replace-with-your-api-key
KAPSO_PHONE_NUMBER_ID=replace-with-your-sender-id
WHATSAPP_TEST_RECIPIENT=replace-with-your-test-recipient

Asegúrate de que Git ignore el archivo:

.env

Bun carga .env automáticamente. No necesitas importar dotenv en este proyecto.

Envía el mensaje

Reemplaza el contenido inicial de index.ts con este cambio específico:

-console.log("Hello via Bun!");
+import { WhatsAppClient } from "@kapso/whatsapp-cloud-api";
+
+const kapsoApiKey = process.env.KAPSO_API_KEY;
+const phoneNumberId = process.env.KAPSO_PHONE_NUMBER_ID;
+const recipient = process.env.WHATSAPP_TEST_RECIPIENT;
+
+if (!kapsoApiKey || !phoneNumberId || !recipient) {
+  throw new Error("Missing Kapso or WhatsApp configuration");
+}
+
+const kapso = new WhatsAppClient({
+  baseUrl: "https://api.kapso.ai/meta/whatsapp",
+  kapsoApiKey,
+});
+
+const response = await kapso.messages.sendText({
+  phoneNumberId,
+  to: recipient,
+  body: "Hello from Bun!",
+});
+
+console.log("Message accepted:", response.messages[0]?.id);

Ejecútalo una vez:

bun run index.ts

Cada ejecución envía otro mensaje, así que no ejecutes este script de un solo uso en modo watch.

Entiende sendText

sendText necesita tres campos del mensaje:

  • phoneNumberId selecciona el remitente empresarial de WhatsApp.
  • to selecciona al destinatario que dio su consentimiento, en formato internacional.
  • body es el texto que se entrega a WhatsApp.

El baseUrl del cliente dirige la solicitud mediante Kapso. kapsoApiKey autentica tu proyecto de Kapso.

Verifica el resultado

Comprueba los tres puntos:

  1. El script termina sin lanzar una excepción y muestra un ID de mensaje.
  2. El mensaje llega al teléfono de prueba autorizado.
  3. La conversación aparece en el Inbox de Kapso.

Una solicitud aceptada por la API no equivale a una entrega. Una aplicación de producción también debe procesar los eventos de estado sent, delivered, read y failed.

Errores comunes

Síntoma Causa probable Solución
401 o 403 La clave de API falta, no es válida o fue revocada Crea una clave de proyecto válida y reinicia el proceso
Remitente incorrecto o no encontrado Se usó el número visible en lugar del Phone Number ID Copia el ID técnico desde Kapso
Se rechaza el envío desde el sandbox El destinatario no está activo en el sandbox Vuelve a activar el mismo teléfono de prueba
Se rechaza el mensaje de formato libre La ventana de atención de 24 horas está cerrada Usa una plantilla aprobada para reabrir la conversación
El script finaliza correctamente, pero no muestra nada La versión del video no registra la respuesta Agrega el registro del ID de mensaje que se muestra arriba

Nunca incluyas .env en un commit, escribas directamente un destinatario real en el código ni publiques una credencial en una captura de pantalla o grabación. Revoca cualquier clave que haya quedado expuesta.

Del script a la aplicación

El repositorio final usa el mismo WhatsAppClient y la misma llamada a sendText. En lugar de escribir directamente un destinatario de prueba en el código, obtiene el destino de la respuesta a partir de un webhook entrante. Las siguientes lecciones construyen ese ciclo de recepción y respuesta.

Recursos

Del video al código

Código de esta lección

Los cambios de este paso, comparados con la lección anterior.

Ver commit en GitHub
crafter-station/receptionist-aif9cafbc+86 líneas agregadas−0 líneas eliminadas
.env.example+3−0
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..0fc548b
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,3 @@
+KAPSO_API_KEY=replace-with-your-api-key
+KAPSO_PHONE_NUMBER_ID=replace-with-your-sender-id
+WHATSAPP_TEST_RECIPIENT=replace-with-your-test-recipient
bun.lock+31−0
diff --git a/bun.lock b/bun.lock
new file mode 100644
index 0000000..91d3130
--- /dev/null
+++ b/bun.lock
@@ -0,0 +1,31 @@
+{
+  "lockfileVersion": 1,
+  "configVersion": 1,
+  "workspaces": {
+    "": {
+      "name": "receptionist-ai",
+      "dependencies": {
+        "@kapso/whatsapp-cloud-api": "^0.3.0",
+      },
+      "devDependencies": {
+        "@types/bun": "^1.3.0",
+        "typescript": "^5.9.3",
+      },
+    },
+  },
+  "packages": {
+    "@kapso/whatsapp-cloud-api": ["@kapso/whatsapp-cloud-api@0.3.0", "", { "dependencies": { "zod": "^4.1.11" } }, "sha512-j4PBmpT+7tDpdmcBy7hRWkCfz2w7tvW5loGNgFBX4iCdVBKT2XNjfAUnjlx65tFToWV65AMPUTY5ztDKV31xhQ=="],
+
+    "@types/bun": ["@types/bun@1.4.2", "", { "dependencies": { "bun-types": "1.4.2" } }, "sha512-GimotNn7+ZV0uVArItBbriZsR1oNf0+WTzPkdcFrzShI7k2norL0uzEaJT8T33dWr7O/c9ZDuAFQrctKCi72oQ=="],
+
+    "@types/node": ["@types/node@26.5.0", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-dVSGpriSoCgz8WnDNTuSSuSv1PC/ALXihO4ulRZt7Md8k9mlbdin3lGOcDE8SnWOgf513ByWlXd7BK4azmyg/A=="],
+
+    "bun-types": ["bun-types@1.4.2", "", { "dependencies": { "@types/node": "*" } }, "sha512-bxV1FgK7yBIzjRe5zBozIM4Bem11ZJcCXSrjWRG3YWLt8yFDePu4cLjpebO8OvPeIE9trbyPF4fuj3Cia4Fj3w=="],
+
+    "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
+
+    "undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="],
+
+    "zod": ["zod@4.5.4", "", {}, "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA=="],
+  }
+}
index.ts+22−0
diff --git a/index.ts b/index.ts
new file mode 100644
index 0000000..1cdbedf
--- /dev/null
+++ b/index.ts
@@ -0,0 +1,22 @@
+import { WhatsAppClient } from "@kapso/whatsapp-cloud-api";
+
+const kapsoApiKey = process.env.KAPSO_API_KEY;
+const phoneNumberId = process.env.KAPSO_PHONE_NUMBER_ID;
+const recipient = process.env.WHATSAPP_TEST_RECIPIENT;
+
+if (!kapsoApiKey || !phoneNumberId || !recipient) {
+  throw new Error("Missing Kapso or WhatsApp configuration");
+}
+
+const kapso = new WhatsAppClient({
+  baseUrl: "https://api.kapso.ai/meta/whatsapp",
+  kapsoApiKey,
+});
+
+const response = await kapso.messages.sendText({
+  phoneNumberId,
+  to: recipient,
+  body: "Hello from Bun!",
+});
+
+console.log("Message accepted:", response.messages[0]?.id);
package.json+16−0
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..502a6b5
--- /dev/null
+++ b/package.json
@@ -0,0 +1,16 @@
+{
+  "name": "receptionist-ai",
+  "type": "module",
+  "private": true,
+  "scripts": {
+    "start": "bun run index.ts",
+    "check": "tsc --noEmit"
+  },
+  "dependencies": {
+    "@kapso/whatsapp-cloud-api": "^0.3.0"
+  },
+  "devDependencies": {
+    "@types/bun": "^1.3.0",
+    "typescript": "^5.9.3"
+  }
+}
tsconfig.json+14−0
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..6c47934
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,14 @@
+{
+  "compilerOptions": {
+    "target": "ESNext",
+    "module": "Preserve",
+    "moduleResolution": "bundler",
+    "types": [
+      "bun"
+    ],
+    "strict": true,
+    "skipLibCheck": true,
+    "noEmit": true,
+    "noUncheckedIndexedAccess": true
+  }
+}