Integração

API de WhatsApp para PHP

Envie mensagens de WhatsApp de qualquer projeto PHP com cURL, sem dependência externa.

<?php
$ch = curl_init("https://zapixo.com.br/api/v1/messages/text");

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("ZAPIXO_API_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "instance" => "meu-site",
        "number"   => "5511999999999",
        "text"     => "Olá do PHP!",
    ]),
]);

$resposta = curl_exec($ch);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status !== 200) {
    error_log("Zapixo falhou ({$status}): {$resposta}");
}

$dados = json_decode($resposta, true);
echo $dados["messageId"] ?? "sem id";

Em PHP, a API do Zapixo é uma chamada HTTP com JSON: dá para usar o cURL que já vem na maioria das instalações, ou o Guzzle se o projeto usa Composer. Não existe SDK para instalar.

Para receber mensagens, basta um arquivo PHP acessível por HTTPS. Esta página cobre os dois lados — enviar e receber — e o que costuma quebrar quando a integração entra em produção.

O que dá para fazer com PHP e WhatsApp

  • Aviso do sistema que já existe

    A loja ou o ERP em PHP avisa pedido, cobrança e entrega sem trocar de linguagem nem subir outro serviço.

  • Formulário do site

    O contato enviado pelo site vira mensagem no WhatsApp do vendedor, com nome e interesse.

  • Atendimento no painel da empresa

    O webhook grava a mensagem recebida no banco, e a equipe responde pela tela que já usa.

  • Rotina no cron

    Um script agendado envia lembretes do dia e marca o que já saiu, para não repetir.

Enviar mensagens pelo PHP

  1. Guarde a chave fora do código

    Gere a chave no painel e leia de variável de ambiente, como ZAPIXO_API_KEY — nunca de arquivo que vai para o repositório. Ela começa com zpx_.

  2. Envio com cURL

    Sem dependência externa. A função limpa o número e devolve o status junto com a resposta:

    function enviarWhatsApp(string $instance, string $numero, string $texto): array
    {
        $ch = curl_init('https://zapixo.com.br/api/v1/messages/text');
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 15,
            CURLOPT_HTTPHEADER     => [
                'Authorization: Bearer ' . getenv('ZAPIXO_API_KEY'),
                'Content-Type: application/json',
            ],
            CURLOPT_POSTFIELDS => json_encode([
                'instance' => $instance,
                'number'   => preg_replace('/\D/', '', $numero),
                'text'     => $texto,
            ]),
        ]);
    
        $corpo  = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
    
        return ['status' => $status, 'dados' => json_decode((string) $corpo, true)];
    }
  3. Com Guzzle

    Com Composer, o Guzzle deixa o código mais curto. http_errors desligado faz o 4xx e o 5xx voltarem como resposta, em vez de exceção:

    $zapixo = new \GuzzleHttp\Client([
        'base_uri' => 'https://zapixo.com.br/api/v1/',
        'timeout'  => 15,
        'headers'  => ['Authorization' => 'Bearer ' . getenv('ZAPIXO_API_KEY')],
    ]);
    
    $res = $zapixo->post('messages/text', [
        'json'        => ['instance' => 'meu-site', 'number' => '5511999999999', 'text' => 'Olá!'],
        'http_errors' => false,
    ]);
    
    $dados = json_decode((string) $res->getBody(), true);
  4. Leia a resposta

    Deu certo, volta status 200 com { "success": true, "messageId": "..." }. Para imagem, use /messages/media com mediaUrl (link público do arquivo) e caption, que é opcional.

Receber mensagens no PHP

  1. Cadastre a URL no painel

    Abra a instância no painel e cole a URL do seu arquivo em Webhook de mensagens. Precisa ser HTTPS. O Zapixo não assina as requisições, então ponha um segredo na própria URL e confira no código: https://seusite.com/webhook-zapixo.php?chave=....

  2. O arquivo que recebe

    Confere o segredo, devolve o 200 logo e só depois processa. O evento de mensagem nova é messages.upsert:

    <?php
    // webhook-zapixo.php
    $segredo = getenv('ZAPIXO_WEBHOOK_SECRET');
    if (!$segredo || !hash_equals($segredo, (string) ($_GET['chave'] ?? ''))) {
        http_response_code(401);
        exit;
    }
    
    $payload = json_decode(file_get_contents('php://input'), true) ?: [];
    $data    = $payload['data'] ?? [];
    $key     = $data['key'] ?? [];
    
    http_response_code(200);
    if (function_exists('fastcgi_finish_request')) {
        fastcgi_finish_request(); // entrega o 200 e continua rodando
    }
    
    if (($payload['event'] ?? '') !== 'messages.upsert' || !empty($key['fromMe'])) {
        exit;
    }
    
    $numero = explode('@', $key['remoteJid'] ?? '')[0];
    $msg    = $data['message'] ?? [];
    $texto  = $msg['conversation'] ?? ($msg['extendedTextMessage']['text'] ?? '');
    
    processarMensagem($key['id'] ?? '', $numero, $texto);
  3. Sem PHP-FPM

    fastcgi_finish_request só existe com PHP-FPM. Em outro ambiente, grave o evento numa tabela e responda; um cron ou uma fila processa depois. Assim a resposta sai sempre dentro do prazo.

Erros comuns e como resolver

Mensagem processada duas vezes
Se o arquivo não devolver 2xx em até 10 segundos, o Zapixo tenta de novo — até 3 tentativas. Guarde key.id numa coluna com índice único e ignore o que já estiver lá.
O bot responde a si mesmo
Mensagens enviadas pela própria instância também chegam, com fromMe: true. Sem esse filtro, a resposta do bot dispara outra resposta.
Mensagem de grupo
Grupo chega com remoteJid terminando em @g.us. Se o sistema só atende conversa individual, descarte.
Status 0 no cURL
Falha de rede ou de DNS não gera status HTTP: curl_exec devolve false e o status fica 0. Trate o 0 como erro de conexão e consulte curl_error() antes de fechar o handle para saber o motivo.
Lista grande estoura o tempo
Mandar a lista inteira num só script esbarra no max_execution_time e no limite de 60 requisições por minuto por chave. Envie em lotes pelo cron, marcando o que já saiu. No 429, espere até o horário de X-RateLimit-Reset.
Erros 401, 404 e 502
401: chave errada ou sem o Bearer na frente. 404: instance não bate com o nome no painel. 502: a entrega ao WhatsApp falhou, e o motivo vem em details.

Perguntas frequentes

Precisa de Composer para usar o Zapixo em PHP?

Não. O cURL resolve sozinho; o Guzzle é opcional.

Funciona em hospedagem compartilhada?

Para enviar, sim, desde que o cURL esteja habilitado e a hospedagem permita conexão de saída. Para receber, o endereço precisa ser HTTPS.

O webhook do Zapixo tem assinatura?

Não. Proteja o arquivo com um segredo na URL e confira com hash_equals em cada requisição.

Consigo enviar imagem pelo PHP?

Sim, pelo endpoint /api/v1/messages/media, com mediaUrl (link público do arquivo) e caption opcional.

O trial tem limite de mensagens?

Tem. Ao atingir o limite, a API responde 402 com o link para assinar.

Leia também