Recadu Guia da API

Instâncias e pareamento

Uma instância é um número de WhatsApp conectado ao Recadu como aparelho vinculado. O número continua no celular; o Recadu ocupa uma das 4 vagas de "Aparelhos conectados" e aparece lá como Recadu.

Criar

curl -X POST https://api.recadu.com.br/v1/instances \
  -H "Authorization: Bearer $GW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "loja-centro", "interactive_mode": "native+text"}'
Campo
name obrigatório Único na conta
kind web (padrão) ou sandbox sandbox: veja abaixo
interactive_mode native+text (padrão), native ou text Como botões e listas saem: veja interativos

O número de instâncias depende do plano; acima dele, 409 instance-limit-reached.

Parear

Por QR

curl -X POST https://api.recadu.com.br/v1/instances/ins_.../pairing \
  -H "Authorization: Bearer $GW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"method": "qr"}'
{
  "instance_id": "ins_...",
  "state": "pairing",
  "qr": {
    "code": "2@AbC...",
    "expires_in_s": 20,
    "image": "data:image/png;base64,iVBORw0..."
  }
}

qr.image vai direto num <img src>. O WhatsApp troca o QR a cada ~20 s: para mostrar sempre o atual, use o stream (abaixo) ou consulte GET /v1/instances/{id}/pairing de novo.

No celular: WhatsApp → Configurações → Aparelhos conectados → Conectar um aparelho, e aponte para o QR.

Por código

Quando não dá para ler o QR (o celular é o mesmo aparelho que mostra a tela, por exemplo):

curl -X POST https://api.recadu.com.br/v1/instances/ins_.../pairing \
  -H "Authorization: Bearer $GW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"method": "code", "phone": "5537999990000"}'
# {"state": "pairing", "pairing_code": "ABCD1234", ...}

No celular: Aparelhos conectados → Conectar um aparelho → Conectar com número de telefone e digite o código.

Acompanhar ao vivo (SSE)

curl -N https://api.recadu.com.br/v1/instances/ins_.../pairing/stream \
  -H "Authorization: Bearer $GW_API_KEY"
event: qr
data: {"code": "2@...", "expires_in_s": 20, "image": "data:image/png;base64,..."}

event: paired
data: {...}

event: connected
data: {...}

O stream manda um qr a cada troca e termina no connected. Linhas : ping a cada 15 s mantêm a conexão aberta. No navegador, EventSource não manda cabeçalhos: faça o stream passar pelo seu servidor, que acrescenta a chave.

Instância já pareada responde 409 already-paired: desconecte antes (POST .../logout).

Estados

state Significa O que fazer
pending_pair Criada, nunca pareada (ou pareamento desfeito) Parear
connecting Conectando ou reconectando Esperar. Se durar, o celular provavelmente está sem internet
connected Pronta para enviar e receber —
disconnected Caiu (internet, WhatsApp fora) Reconecta sozinha. POST .../restart força
logged_out O aparelho foi desconectado no celular Parear de novo
banned O WhatsApp bloqueou o número Não há como reverter pelo Recadu

GET /v1/instances/{id} traz o state gravado e, em live, o estado consultado agora na conexão. Mudanças também chegam por webhook (instance.connected, instance.disconnected...).

Mensagens enviadas enquanto a instância está fora ficam na fila e saem quando ela volta, até 15 minutos; depois falham com expired.

Outras operações

Rota Faz
PATCH /v1/instances/{id} Muda name, interactive_mode ou a policy (políticas)
POST /v1/instances/{id}/restart Reconecta ao WhatsApp
POST /v1/instances/{id}/logout Desconecta o aparelho (o número sai do Recadu; precisa parear de novo)
DELETE /v1/instances/{id} Desconecta e remove a instância
GET /v1/instances/{id}/contacts/{phone} Confere se o número tem WhatsApp: {"exists": true, "jid": "...", "phone": "..."}
POST /v1/instances/{id}/chats/{chat}/presence Mostra "digitando" (typing), "gravando" (recording) ou para (paused)
POST /v1/instances/{id}/chats/{chat}/read Marca mensagens recebidas como lidas (wa_message_ids)
GET /v1/instances/{id}/health Saúde do número
GET /v1/instances/{id}/availability?month=AAAA-MM Disponibilidade

Sandbox

Uma instância sandbox serve para integrar e testar sem celular e sem risco para um número de verdade:

curl -X POST https://api.recadu.com.br/v1/instances \
  -H "Authorization: Bearer $GW_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "teste-integracao", "kind": "sandbox"}'

Para simular o contato respondendo:

# mensagem de texto recebida -> message.received
curl -X POST https://api.recadu.com.br/v1/instances/ins_.../sandbox/inbound \
  -H "Authorization: Bearer $GW_API_KEY" -H "Content-Type: application/json" \
  -d '{"from": "5537999990000", "text": "Oi, quero fazer um pedido"}'

# clique num botão -> message.interactive_reply
curl -X POST https://api.recadu.com.br/v1/instances/ins_.../sandbox/inbound \
  -H "Authorization: Bearer $GW_API_KEY" -H "Content-Type: application/json" \
  -d '{"from": "5537999990000", "text": "Confirmar", "reply": {"option_id": "confirmar", "label": "Confirmar", "source": "native_flow"}}'

text é sempre obrigatório (no clique, é o texto que o contato vê). reply.source pode ser native_flow, button, list ou poll. Para responder a uma mensagem específica, mande reply.in_reply_to_wa_message_id com o wa_message_id dela. Para simular uma resposta citando uma mensagem, use quoted_wa_message_id. Mandar "2" em text depois de um menu numerado também vira message.interactive_reply, como no WhatsApp de verdade.

Simular numa instância web responde 409 not-sandbox.