O cliente TypeScript
Um método tipado por endpoint, gerado das mesmas definições que respondem às suas requisições. O que o seu editor diz é o que a API faz. Zero dependências, ESM, Node 20+.
Instale
npm i @whatsapi.sh/sdkO cliente recebe a sua chave uma vez e leva ela pra todo lado. Depois disso é só chamar métodos. Cada método, argumento e campo chega com a documentação que você está lendo agora anexada, então passar o mouse no editor rende mais que abrir outra aba. TypeScript é opcional: o pacote é ESM puro e funciona em JavaScript, inclusive com require() no Node 22.12+.
Envie alguma coisa
import { Whatsapi } from "@whatsapi.sh/sdk";
const wa = new Whatsapi({ apiKey: process.env.WHATSAPI_KEY });
const message = await wa.sendMessage({
to: "+5511988887777",
text: "Your table is ready.",
});
console.log(message.id, message.quotaRemaining);Todo método recebe um objeto e devolve exatamente o que o endpoint responde, incluindo quotaRemaining, então um medidor de uso não precisa de uma segunda chamada.
Lidando com os erros
import { WhatsapiError } from "@whatsapi.sh/sdk";
try {
await wa.sendMessage({ to, text });
} catch (error) {
if (!(error instanceof WhatsapiError)) throw error;
if (error.code === "PAYMENT_REQUIRED") return offerAnUpgrade();
if (error.code === "NUMBER_NOT_CONNECTED") return askForARepair();
if (error.code === "GATEWAY_TIMEOUT") return watchFor(error.messageId);
throw error;
}As falhas chegam como WhatsapiError, carregando o código da própria API, o status HTTP, um retryAfter sempre que dá para saber a espera, e o id da requisição para citar no suporte.
Quando o envio fica sem confirmação
GATEWAY_TIMEOUT significa que o WhatsApp não confirmou a tempo. Não sabemos se a mensagem chegou. Se error.messageId vier na resposta, acompanhe esse id no webhook message.status para saber se ela chegou. Confira a conversa antes de enviar de novo. Outro envio com uma chave nova, ou sem chave, pode duplicar a mensagem. Com a mesma idempotencyKey, você recebe a mesma resposta, sem um segundo envio.
O que tenta de novo, e o que nunca tenta
const message = await wa.sendMessage(
{ to: "+5511988887777", text: "Your table is ready." },
{ idempotencyKey: order.id },
);Dê a um envio uma idempotencyKey, um id que você escolhe, como o id de um pedido. Se o envio falhar sem resposta ou com um 5xx, o cliente manda de novo com a mesma chave de idempotência, e a API responde com o primeiro resultado em vez de mandar a mensagem duas vezes. Se o primeiro envio ainda estiver rodando, a API responde 409 com um Retry-After, e o cliente espera esse tempo e tenta de novo. Guarde essa chave junto com o que você está enviando, para que uma nova tentativa depois de uma queda use a mesma. Leitura também tenta de novo depois de um 5xx ou de uma resposta perdida. Envio sem chave de idempotência nunca é repetido depois de um 5xx ou de uma resposta perdida: seria uma segunda mensagem de verdade pra uma pessoa de verdade. Um 429 que libera em até 10 segundos é repetido em qualquer chamada, porque nada rodou.
Confira o que chega
import { verifyWebhook } from "@whatsapi.sh/sdk";
const event = await verifyWebhook({
payload: rawBody, // the raw bytes, not the parsed body
signature: req.header("x-whatsapi-signature"),
secret: process.env.WHATSAPI_WEBHOOK_SECRET,
});
if (event.type === "message.created") {
await reply(event.data.number.id, event.data.message.text);
}verifyWebhook confere a assinatura, recusa entrega repetida e devolve o evento já estreitado pelo type, então os campos do payload são conhecidos antes de você tocar neles.
Construindo um agente?
Então você quer MCP, não este pacote: as mesmas operações como ferramentas, com a mesma chave. O cliente é pros aplicativos que você mesmo escreve.