---
title: "SDK de JavaScript y TypeScript de WAME: WhatsApp tipado, en los tres canales"
description: "El SDK oficial de WAME en Node.js y TypeScript: envío tipado con autocompletado, los tres canales de Meta en la misma llamada y el webhook en el sobre estándar. Instalación, primer envío y el handler que sirve para los tres."
url: "https://wame.api.br/blog/sdk-javascript-typescript-whatsapp"
language: "pt-BR"
og:type: "article"
published_time: "2026-09-10"
modified_time: "2026-09-10"
author: "Raphael Serafim"
keywords: "sdk whatsapp javascript, api whatsapp node js, whatsapp typescript, npm whatsapp api, enviar whatsapp node, librería whatsapp node"
reading_time: "9 min de lectura"
---

# SDK de JavaScript y TypeScript de WAME: WhatsApp tipado, en los tres canales

> El SDK oficial de WAME en Node.js y TypeScript: envío tipado con autocompletado, los tres canales de Meta en la misma llamada y el webhook en el sobre estándar. Instalación, primer envío y el handler que sirve para los tres.

**Si tu sistema es Node, el SDK de WAME tipa la integración completa** — los tres canales de Meta, el envío, la instancia y el webhook. Esta guía va del `npm install` al handler recibiendo mensajes.

## Instalación

```bash
npm install @raphaelvserafim/client-api-whatsapp
```

```ts
import { Wame, TypeMessage } from '@raphaelvserafim/client-api-whatsapp';

const wa = new Wame({
  server: 'https://server.wame.api.br',
  key: process.env.WAME_KEY!,
});
```

Los tipos vienen en el paquete. No hay `@types` aparte que instalar.

## Primer envío

```ts
const to = '525512345678';   // internacional, solo dígitos

await wa.message.send({
  type: TypeMessage.TEXT,
  body: { to, text: 'Tu pedido #1042 salió para entrega 🚚' },
});
```

`TypeMessage` es un enum, y es lo que hace el trabajo pesado en el editor: el autocompletado lista los tipos disponibles y el cuerpo esperado cambia según el tipo elegido.

```ts
// el compilador lo rechaza: un mensaje de texto no tiene `url`
await wa.message.send({
  type: TypeMessage.TEXT,
  body: { to, url: 'https://ejemplo.com/foto.jpg' },
});
```

Ese error, en un proyecto sin tipos, sería una respuesta 400 en producción a las tres de la mañana.

## Archivos

```ts
await wa.message.send({
  type: TypeMessage.IMAGE,
  body: { to, url: 'https://ejemplo.com/factura.jpg', caption: 'Tu factura' },
});

await wa.message.send({
  type: TypeMessage.AUDIO,
  body: { to, url: 'https://ejemplo.com/audio.mp3' },
});
```

## Los tres canales

```ts
await wa.message.send({
  type: TypeMessage.TEXT,
  body: { to, text: 'Hola', provider: 'instagram' },
});
```

Un campo. Sin `provider` va a WhatsApp; con `instagram` o `messenger` va al otro canal — [misma instancia, misma key, mismo webhook](/blog/api-instagram-messenger-misma-api-whatsapp).

## Instancia y webhook

```ts
// Conectar (API no oficial)
const qr = await wa.instance.connect();
const code = await wa.instance.pairingCode('525512345678');

// Estado
const info = await wa.instance.info();

// Operación
await wa.instance.logout();
await wa.instance.restart();
await wa.instance.resync();
```

Configurar a dónde van los eventos:

```ts
await wa.instance.updateWebhook({
  allowWebhook: true,
  allowNumber: 'all',
  webhookMessage: 'https://tusistema.com/webhook/wame',
  webhookFormat: 'meta',   // sobre de la Cloud API — el mismo para los 3
});

const stats = await wa.instance.webhookStatistics();
```

`webhookStatistics()` vale conocerlo: cuando el webhook "deja de funcionar", muestra si las entregas están saliendo y fallando o si ni siquiera se están intentando — y eso decide de qué lado buscar. Es el paso siguiente a [la prueba con webhook.site](/blog/webhook-whatsapp-no-llega-como-probar).

## El handler para los tres canales

```ts
import express from 'express';

type EventoWame = {
  provider: 'whatsapp' | 'instagram' | 'messenger';
  entry: Array<{
    changes: Array<{
      value: {
        messages?: Array<{
          from: string;
          id: string;
          type: string;
          text?: { body: string };
        }>;
        statuses?: Array<{ id: string; status: string }>;
      };
    }>;
  }>;
};

const app = express();
app.use(express.json());

app.post('/webhook/wame', (req, res) => {
  res.sendStatus(200);                     // primero esto, siempre
  procesar(req.body as EventoWame).catch(console.error);
});

async function procesar(evento: EventoWame) {
  const value = evento.entry?.[0]?.changes?.[0]?.value;

  // `statuses` es entrega o lectura, no un mensaje nuevo.
  const msg = value?.messages?.[0];
  if (!msg || msg.type !== 'text') return;

  await registrar({
    canal: evento.provider,
    de: msg.from,
    texto: msg.text!.body,
    messageId: msg.id,
  });
}
```

Un handler. Tres canales. El único campo que varía es `provider`.

## En Next.js y serverless

Solo del lado del servidor:

```ts
// app/api/webhook/wame/route.ts
export async function POST(req: Request) {
  const evento = await req.json();
  after(() => procesar(evento));   // responde ya, procesa después
  return Response.json({ ok: true });
}
```

**Nunca llames al SDK desde el cliente.** La key de la instancia iría al bundle y cualquier visitante podría enviar mensajes por tu número.

En serverless hay una segunda trampa: si respondes y la función termina, el procesamiento en segundo plano muere con ella. Usa el mecanismo de la plataforma para trabajo posterior a la respuesta (`after` en Next, `waitUntil` en runtimes edge) o empuja a una cola.

## Manejo de errores

```ts
try {
  await wa.message.send({ type: TypeMessage.TEXT, body: { to, text } });
} catch (e) {
  // Número sin WhatsApp, instancia desconectada, límite alcanzado.
  // El error trae el código; trata cada caso, no te lo comas en un catch mudo.
  console.error('falló el envío a', to, e);
  await encolarParaReintento({ to, text });
}
```

Vale comprobar antes de enviar, cuando la lista viene de un alta de cliente:

```ts
const existe = await wa.contact.checkNumber(to);
if (!existe) return marcarInvalido(to);
```

Eso separa una lista que entrega de una lista que quema reputación — el tema de [opt-in, limpieza y opt-out](/blog/lista-contactos-optin-optout-whatsapp).

## Conclusión

La ganancia del SDK tipado no es escribir menos: es el compilador rechazando el payload equivocado antes del deploy. Con tres canales en el mismo contrato, eso vale por tres.

Si trabajas en PHP, el [SDK de PHP](/blog/sdk-php-whatsapp-instagram-messenger) cubre lo mismo. La referencia completa está en [docs/sdk/ts](/docs/sdk/ts).

## Perguntas frequentes

### ¿Cómo instalo el SDK de JavaScript de WAME?

Con npm install @raphaelvserafim/client-api-whatsapp. El paquete ya incluye las definiciones de tipos, así que funciona en JavaScript puro y en TypeScript sin instalar @types por separado.

### ¿El SDK funciona con TypeScript?

Sí, y es donde más rinde. Los tipos de mensaje son un enum y el cuerpo de cada tipo está tipado, así que el editor muestra los campos válidos y el compilador marca error si mandas una url en un mensaje de texto.

### ¿Se puede usar en Next.js o en serverless?

Sí, siempre que la llamada ocurra en el servidor: route handler, server action o función serverless. Nunca en el cliente, porque la key de la instancia quedaría expuesta en el bundle y cualquiera podría enviar mensajes en nombre de tu número.

### ¿Cómo envío a Instagram y Messenger?

Con el mismo método send, agregando el campo provider en el cuerpo del mensaje. WhatsApp es el valor por defecto; indicar instagram o messenger dirige la misma llamada al otro canal, porque la instancia cubre los tres.

### ¿El SDK cubre la creación de instancias?

Sí. El objeto instance expone conexión por código QR y por pairing code, información, logout, restart, resync y configuración de webhook — suficiente para aprovisionar y operar cuentas sin que nadie abra un panel.
