Integração
API de WhatsApp para Laravel
Integre WhatsApp em aplicações Laravel com HTTP Client.
// Laravel — Http Facade
use Illuminate\Support\Facades\Http;
Http::withToken(config('services.zapixo.key'))
->post('https://zapixo.com.br/api/v1/messages/text', [
'instance' => 'laravel-app',
'number' => $telefone,
'text' => $mensagem,
]);No Laravel, o Zapixo cabe no que o framework já tem: o Http facade envia, uma rota de API recebe o webhook e um job na fila processa a mensagem fora da requisição. Nada para instalar além do próprio Laravel.
Se o projeto não usa Laravel, a guia de PHP mostra o mesmo com cURL.
O que dá para fazer com Laravel e WhatsApp
Notificação a partir de evento
Pedido pago dispara um listener, que coloca o envio na fila sem travar a tela do usuário.
Atendimento no painel
O webhook grava a mensagem, e a equipe responde pela tela do próprio sistema.
Disparo agendado
O Scheduler monta a lista do dia e distribui os jobs no tempo, dentro do limite da API.
Bot com regra de negócio
O job consulta os models e responde com o dado real: pedido, agenda, saldo.
Enviar mensagens pelo Laravel
Configure em services.php
Leia sempre por
config(), nunca porenv()fora dos arquivos de configuração: depois dephp artisan config:cache, oenv()passa a devolvernull.// config/services.php 'zapixo' => [ 'key' => env('ZAPIXO_API_KEY'), 'webhook_secret' => env('ZAPIXO_WEBHOOK_SECRET'), ],Envio com o Http facade
withTokenmonta o headerAuthorization: Bearersozinho:use Illuminate\Support\Facades\Http; $resposta = Http::withToken(config('services.zapixo.key')) ->timeout(15) ->post('https://zapixo.com.br/api/v1/messages/text', [ 'instance' => 'laravel-app', 'number' => preg_replace('/\D/', '', $telefone), 'text' => $mensagem, ]); if ($resposta->failed()) { report(new \RuntimeException("Zapixo {$resposta->status()}: {$resposta->body()}")); }Envie de dentro de um job
Chamada HTTP no meio da requisição deixa o usuário esperando. No job, o
429devolve o trabalho para a fila em vez de perder a mensagem (imports omitidos):class EnviarWhatsApp implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public int $tries = 5; public function __construct(public string $numero, public string $texto) {} public function handle(): void { $r = Http::withToken(config('services.zapixo.key')) ->timeout(15) ->post('https://zapixo.com.br/api/v1/messages/text', [ 'instance' => 'laravel-app', 'number' => $this->numero, 'text' => $this->texto, ]); if ($r->status() === 429) { $this->release(60); return; } $r->throw(); } }
Receber mensagens no Laravel
Crie a rota de API
Em
routes/api.php— no Laravel 11 em diante, o arquivo é criado comphp artisan install:api. Rota de API não passa pela verificação de CSRF, que recusaria o POST do Zapixo:use App\Http\Controllers\ZapixoWebhook; Route::post('/webhooks/zapixo', ZapixoWebhook::class);Cole a URL no painel
Em Webhook de mensagens, com o segredo no fim:
https://seuapp.com/api/webhooks/zapixo?chave=SEU_SEGREDO. O Zapixo não assina as requisições; o segredo na URL é a proteção.O controller
Confere o segredo, filtra
fromMe, põe o trabalho na fila e responde na hora:class ZapixoWebhook { public function __invoke(Request $request) { $segredo = config('services.zapixo.webhook_secret'); abort_unless($segredo && hash_equals($segredo, (string) $request->query('chave')), 401); if ($request->input('event') === 'messages.upsert' && ! $request->boolean('data.key.fromMe')) { ProcessarMensagemZapixo::dispatch($request->input('data')); } return response()->noContent(); } }O job, sem processar duas vezes
Cache::addsó grava se a chave não existir — é o jeito mais curto de ignorar a repetição de um webhook:public function handle(): void { $id = $this->data['key']['id'] ?? null; if (! $id || ! Cache::add("zapixo:msg:{$id}", true, now()->addDay())) { return; // já processada } $numero = explode('@', $this->data['key']['remoteJid'])[0]; $msg = $this->data['message'] ?? []; $texto = $msg['conversation'] ?? ($msg['extendedTextMessage']['text'] ?? ''); // a regra do seu negócio entra aqui }
Erros comuns e como resolver
- O webhook responde 419
- É a proteção de CSRF: a rota foi para
routes/web.php. Mova pararoutes/api.php, ou exclua o caminho da verificação. - `env()` devolvendo null em produção
- Com a configuração em cache, só
config()enxerga os valores. Troque todoenv('ZAPIXO_...')fora deconfig/porconfig('services.zapixo...'). - Job rodando dentro da requisição
- Com
QUEUE_CONNECTION=sync, o job roda na hora e o webhook passa dos 10 segundos. Usedatabaseouredise deixe umphp artisan queue:workrodando. - Mensagem processada duas vezes
- Se a rota não devolver 2xx em até 10 segundos, o Zapixo tenta de novo, até 3 vezes. O
Cache::addcomkey.iddo exemplo resolve. - 429 em disparo para lista
- 60 requisições por minuto por chave. Distribua os jobs com
->delay(now()->addSeconds($i))e deixe oreleasedo job cuidar do que passar do limite. - Erros 401, 404 e 502
401: chave errada ou vazia — confiraconfig('services.zapixo.key').404:instancenão bate com o nome no painel.502: a entrega ao WhatsApp falhou, e o motivo vem emdetails.
Perguntas frequentes
Precisa de pacote para usar o Zapixo no Laravel?
Não. O Http facade, a fila e as rotas do próprio Laravel resolvem.
Funciona no Laravel 10 e no 11?
Funciona. A diferença é a rota de API: do Laravel 11 em diante, routes/api.php é criado com php artisan install:api.
Qual driver de fila usar?
Database basta para começar; Redis quando o volume crescer. O que não pode é sync em produção.
O webhook do Zapixo tem assinatura?
Não. Proteja a rota com um segredo na URL e confira com hash_equals.
O trial tem limite de mensagens?
Tem. Ao atingir o limite, a API responde 402 com o link para assinar.
Leia também
- Webhook WhatsApp: como receber mensagens na sua aplicação
Aprenda a configurar webhooks para receber mensagens, atualizações de status e eventos de conexão do WhatsApp via Zapixo.
- Como proteger a chave da sua API de WhatsApp
Onde guardar a chave, como reagir a um vazamento, por que nunca chamar a API do navegador ou do app, e o que fazer antes de dar acesso a um terceiro.
- Rate limit e fila: disparar WhatsApp em volume sem perder mensagem
Como respeitar o limite de requisições da API, montar uma fila com retentativa, tratar 429 e 502 e garantir que nenhuma mensagem se perca no caminho.