---
title: "API de WhatsApp em Node.js com SDK oficial | D-API"
description: "Integre a API de WhatsApp em Node.js com o SDK d-api-sdk: crie a sessão, leia o QR Code, envie texto e listas e receba o webhook no Express, com TypeScript."
url: https://d-api.cloud/api-whatsapp-nodejs
---

Por linguagem

# API de WhatsApp em Node.js: guia prático com o SDK oficial

Em Node.js, o caminho mais curto é o pacote d-api-sdk: um npm install, uma instância do client e você já cria a conexão, lê o QR Code e envia a primeira mensagem. Este guia cobre o fluxo inteiro em TypeScript, incluindo o webhook no Express e o tratamento de erro.

Por Time de engenharia D-APIAtualizado em 24 de set de 20266 min de leitura

## Por que usar o SDK em vez de montar as requisições

Toda a [API de WhatsApp](https://d-api.cloud/) da D-API é REST, então nada impede que você escreva as chamadas com fetch ou axios. O ganho do SDK aparece no dia a dia: os métodos têm nome de ação (`sessions.create`, `messages.sendText`, `interactive.sendList`), os parâmetros são tipados e o editor avisa quando falta um campo obrigatório antes de o código ir para produção.

Node.js é a única linguagem com biblioteca oficial da D-API. Nas outras stacks a integração é feita com o cliente HTTP da própria linguagem, e o contrato é o mesmo. A página da [integração Node.js SDK](https://d-api.cloud/integrations/nodejs-sdk) resume os módulos disponíveis.

## Instalação e client configurado

Instale o pacote e crie um único client para a aplicação inteira. Guarde a API Key em variável de ambiente; ela vai no header `Authorization` sem o prefixo Bearer, e o SDK cuida disso sozinho.

```
npm install d-api-sdk
```

```
// src/dapi.ts
import { DApi } from 'd-api-sdk'

export const dapi = new DApi({
  apiKey: process.env.DAPI_API_KEY!,
  timeout: 10_000, // padrão é 30000 ms; em rota HTTP prefira algo menor
})
```

O `baseUrl` é opcional e aponta para `https://api.d-api.cloud` por padrão. O parâmetro `timeout` vale para todas as chamadas: quando estoura, o SDK aborta o fetch e lança um erro com status 408. Deixar esse valor explícito evita que uma requisição lenta segure o event loop de uma rota da sua aplicação por meio minuto.

## Criar a conexão e exibir o QR Code

Cada número de WhatsApp é uma sessão, identificada por um `sessionId` que você escolhe. Na criação você já informa a URL do webhook, assim os eventos começam a chegar assim que o número conectar.

```
import { dapi } from './dapi'

await dapi.sessions.create({
  sessionId: 'loja-centro',
  connectionMode: 'qr',
  webhookUrl: 'https://seu-app.com/webhooks/whatsapp/' + process.env.WEBHOOK_TOKEN,
})

const { qrCodeImage } = await dapi.sessions.getQRCode('loja-centro')
// qrCodeImage é um data URI (data:image/png;base64,...)
// basta usar como src de uma <img> no painel do seu cliente
```

O QR expira em poucos segundos e é renovado pela API. Na tela de conexão, consulte `getQRCode` de novo em intervalos curtos até o número conectar, ou ouça o evento `connection.status` no webhook e troque a tela quando `data.status` vier como `connected`. Os detalhes de pareamento, inclusive por código em vez de QR, estão em [API de WhatsApp com QR Code](https://d-api.cloud/api-whatsapp-qr-code).

## Enviar texto e lista com poucas linhas

Com o número conectado, o envio de texto pede três campos: sessão, destino no formato internacional sem o sinal de mais e o conteúdo. A lista interativa acrescenta o texto do botão e as seções com as opções.

```
await dapi.messages.sendText({
  sessionId: 'loja-centro',
  to: '5511999999999',
  text: 'Oi, Ana! Seu pedido 4812 foi aprovado.',
})

await dapi.interactive.sendList({
  sessionId: 'loja-centro',
  to: '5511999999999',
  description: 'Quando prefere receber?',
  buttonText: 'Ver horários',
  sections: [
    {
      title: 'Entrega',
      rows: [
        { rowId: 'manha', title: 'Manhã', description: '8h às 12h' },
        { rowId: 'tarde', title: 'Tarde', description: '13h às 18h' },
      ],
    },
  ],
})
```

O `rowId` é o que volta para o seu sistema quando a pessoa escolhe uma opção, então use valores que o código entenda sem consulta extra. Limites de seções e linhas, e o que o WhatsApp permite em botões, estão em [botões e listas no WhatsApp](https://d-api.cloud/api-whatsapp-botoes-e-listas).

## Tratar erro e timeout

Quando a API responde com status de erro, ela devolve um corpo no formato `{ success: false, error, statusCode }`. O SDK transforma isso em uma exceção do tipo `DApiError`, com `message` vindo do campo `error`, o `status` HTTP e o corpo original em `response`.

```
import type { DApiError } from 'd-api-sdk'

try {
  await dapi.messages.sendText({ sessionId: 'loja-centro', to, text })
} catch (err) {
  const e = err as DApiError
  if (e.status === 408) {
    // timeout do client: a mensagem pode ter saído ou não
    logger.warn({ to, status: e.status }, 'envio sem resposta a tempo')
  } else if (e.status >= 400 && e.status < 500) {
    // payload inválido ou sessão inexistente: tentar de novo não resolve
    logger.error({ status: e.status, error: e.message }, 'envio recusado')
  }
  throw err
}
```

Duas decisões valem ser tomadas cedo. Erro 4xx indica problema no pedido, como campo faltando ou sessão desconectada, e repetir a chamada só gera ruído. Já timeout e 5xx podem ser temporários. Quem manda muito volume costuma colocar o envio em uma fila (BullMQ, por exemplo), assim o request do seu produto responde rápido e o envio acontece em segundo plano.

## Receber o webhook com Express

Mensagens recebidas, confirmações de leitura e mudanças de conexão chegam por POST na URL que você cadastrou. Todo evento tem o mesmo envelope: `event`, `sessionId`, `data`, `timestamp` e `traceId`. A rota abaixo valida o token secreto da URL, responde imediatamente e só depois trata a resposta da lista.

```
import express from 'express'
import { dapi } from './dapi'

const app = express()

app.post('/webhooks/whatsapp/:token', express.json({ limit: '1mb' }), (req, res) => {
  if (req.params.token !== process.env.WEBHOOK_TOKEN) {
    res.sendStatus(401)
    return
  }
  res.sendStatus(200) // responde antes de qualquer trabalho pesado

  const { event, sessionId, data } = req.body
  if (event !== 'messages.received' || data.fromMe) return

  if (data.type === 'list_response') {
    const escolha = data.data.selected_row_id // 'manha' ou 'tarde'
    const numero = data.from.jid.split('@')[0]
    dapi.messages
      .sendText({ sessionId, to: numero, text: 'Combinado, entrega agendada.' })
      .catch((err) => logger.error({ err, traceId: req.body.traceId }, 'falha na resposta'))
  }
})

app.listen(3000)
```

O webhook de WhatsApp não traz assinatura HMAC, por isso o token no caminho da URL faz o papel de segredo. Também dá para conferir o header `User-Agent`, que chega como `Deliverify-Webhook/1.0`, e se o `sessionId` pertence a um cliente seu. Os eventos disponíveis e a política de reenvio estão em [webhook de WhatsApp](https://d-api.cloud/webhook-api-whatsapp).

## Checklist antes de colocar em produção

-   API Key e token do webhook em variáveis de ambiente, nunca no repositório.
-   Timeout do client ajustado ao contexto: menor dentro de rota HTTP, maior em worker.
-   Deduplicação pelo `data.id` da mensagem, porque a mesma entrega pode chegar mais de uma vez se o seu servidor demorar a responder.
-   Log com o `traceId` do evento, que ajuda o suporte a rastrear uma entrega específica.
-   Um `sessionId` por número. Se o seu produto terá uma conexão por cliente, veja como isso se organiza na página de [API de WhatsApp para SaaS](https://d-api.cloud/api-whatsapp-para-saas).

## Perguntas frequentes

### Preciso usar o SDK ou posso chamar a API direto com fetch?

Os dois funcionam. A API é REST e aceita qualquer cliente HTTP. O d-api-sdk só poupa trabalho: já monta a URL, manda o header Authorization, aplica timeout e entrega tipos prontos para TypeScript.

### O d-api-sdk funciona com JavaScript puro, sem TypeScript?

Sim. O pacote é publicado em JavaScript com as definições de tipo junto. Em um projeto sem TypeScript você importa e chama os mesmos métodos, só perde o autocomplete tipado no editor.

### Qual versão do Node.js eu preciso?

O SDK usa o fetch nativo e o AbortController, então precisa de uma versão do Node.js que já traga fetch global, como a 18 ou superior. Em versões antigas o import funciona, mas as chamadas falham.

### Como sei qual opção o cliente escolheu na lista?

A resposta chega no webhook como evento messages.received com type igual a list\_response. Dentro de data.data vem selected\_row\_id, que é o rowId que você definiu ao enviar a lista.

Teste a API de WhatsApp da D-API3 dias grátis, sem cartão.[Começar trial grátis](https://app.d-api.cloud/register)

## Continue lendo

-   [Por linguagemAPI de WhatsApp em Python](https://d-api.cloud/api-whatsapp-python)
-   [Por linguagemAPI de WhatsApp em PHP](https://d-api.cloud/api-whatsapp-php)
-   [Por linguagemAPI de WhatsApp em Laravel](https://d-api.cloud/api-whatsapp-laravel)
-   [Por linguagemAPI de WhatsApp em Java](https://d-api.cloud/api-whatsapp-java)

## Teste a API de WhatsApp da D-API

Trial de 3 dias com acesso completo. Sem cartão, sem fidelidade.

[Começar trial grátis](https://app.d-api.cloud/register)[Ver documentação](https://docs.d-api.cloud/)
