Referência da API WapFlow OTP
Envie e verifique códigos de verificação do seu próprio número do WhatsApp. Todas as respostas são em JSON.
URL base: https://wapflow.net/api/otp/v1
Autenticação
Envie o cabeçalho Authorization: Bearer <key> em cada requisição. Você cria as chaves na página WapFlow OTP do seu painel WapFlow; chaves de produção começam com wfo_live_ e chaves de teste com wfo_test_. A chave é mostrada apenas uma vez, no momento da criação — guarde-a em local seguro e use-a somente no seu servidor.
Uma resposta de sucesso tem o formato { "success": true, ... }; um erro tem o formato { "success": false, "error": { "code": "...", "message": "..." } }.
Enviar código
phone (obrigatório) é o número do destinatário. Opcionais: code_length (4–8), ttl (60–900 s), lang (ex.: tr, en) e app_name. O que você não informar vem das configurações do seu painel.
{
"phone": "905321234567",
"code_length": 6,
"ttl": 300,
"lang": "tr",
"app_name": "Acme"
}
{
"success": true,
"request_id": "req_...",
"phone": "905321234567",
"expires_at": "2026-11-12T10:05:00.000Z",
"status": "sent" // "sent" | "queued"
}
Verificar código
phone e code são obrigatórios. Com request_id, aquela requisição exata é verificada; sem ele, é verificado o código válido mais recente enviado para esse número com esta chave. Após 5 tentativas erradas, a requisição é bloqueada, e um código já verificado não pode ser reutilizado.
{ "request_id": "req_...", "phone": "905321234567", "code": "123456" }
{ "success": true, "valid": true }
{ "success": true, "valid": false,
"reason": "invalid_code", // invalid_code | expired | too_many_attempts | already_verified | not_found
"attempts_left": 3 }
Consultar status
Retorna o status da requisição: queued, sent, delivered, read, failed, verified ou expired.
{ "success": true, "request_id": "req_...", "status": "delivered",
"sent_at": "...", "delivered_at": "...", "verified_at": null }
Testar a conexão
Mostra se a chave é válida, seu plano, o número de contas conectadas e o uso da cota deste mês (o botão "Testar conexão" do plugin WordPress usa este endpoint).
{ "success": true, "plan": "otp-2",
"accounts": { "limit": 2, "connected": 1 },
"quota": { "monthly": 15000, "used": 42, "period": "2026-11" },
"ends_at": "2026-12-12T10:00:00.000Z", "mode": "live" }
Exemplos
Estes exemplos enviam um código e depois verificam o que o usuário digitar. Substitua wfo_live_XXXX pela sua própria chave.
# 1) send
curl -X POST https://wapflow.net/api/otp/v1/send \
-H "Authorization: Bearer wfo_live_XXXX" \
-H "Content-Type: application/json" \
-d '{"phone":"905321234567","app_name":"Acme"}'
# 2) verify
curl -X POST https://wapflow.net/api/otp/v1/verify \
-H "Authorization: Bearer wfo_live_XXXX" \
-H "Content-Type: application/json" \
-d '{"request_id":"req_...","phone":"905321234567","code":"123456"}'<?php
function wapflow_otp(string $path, array $body): array {
$ch = curl_init('https://wapflow.net/api/otp/v1' . $path);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('WAPFLOW_OTP_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($body),
]);
$res = json_decode(curl_exec($ch), true) ?: [];
curl_close($ch);
return $res;
}
$sent = wapflow_otp('/send', ['phone' => '905321234567', 'app_name' => 'Acme']);
// ... kullanıcı kodu girince:
$check = wapflow_otp('/verify', ['request_id' => $sent['request_id'], 'phone' => '905321234567', 'code' => $_POST['code']]);
if (!empty($check['valid'])) { /* giriş başarılı */ }const BASE = 'https://wapflow.net/api/otp/v1';
async function otp(path, body) {
const res = await fetch(BASE + path, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WAPFLOW_OTP_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
return res.json();
}
const sent = await otp('/send', { phone: '905321234567', app_name: 'Acme' });
// ... when the user submits the code:
const check = await otp('/verify', { request_id: sent.request_id, phone: '905321234567', code: '123456' });
if (check.valid) { /* signed in */ }import os
import requests
BASE = "https://wapflow.net/api/otp/v1"
HEADERS = {"Authorization": "Bearer " + os.environ["WAPFLOW_OTP_KEY"]}
def otp(path, body):
return requests.post(BASE + path, json=body, headers=HEADERS, timeout=15).json()
sent = otp("/send", {"phone": "905321234567", "app_name": "Acme"})
# ... when the user submits the code:
check = otp("/verify", {"request_id": sent["request_id"], "phone": "905321234567", "code": "123456"})
if check.get("valid"):
pass # signed inCódigos de erro
| HTTP | Código | Significado |
|---|---|---|
| 400 | invalid_request | O corpo da requisição ou os parâmetros são inválidos. |
| 401 | invalid_key | A chave de API é inválida ou foi revogada. |
| 402 | no_subscription | Esta conta não possui assinatura do WapFlow OTP. |
| 402 | subscription_expired | A assinatura expirou; renove-a. |
| 403 | sales_disabled | O serviço está temporariamente indisponível. |
| 422 | invalid_phone | O número de telefone é inválido. |
| 429 | rate_limited | Limite de requisições excedido; tente novamente após os retry_after segundos indicados na resposta. |
| 429 | quota_exceeded | A cota de códigos deste mês foi esgotada. |
| 429 | daily_limit_reached | O limite diário de envio das contas WhatsApp conectadas foi atingido; tente novamente após os segundos indicados em retry_after na resposta (no dia seguinte, às 00:00, horário de Istambul). Nenhuma cota é consumida. |
| 503 | no_account_connected | Não há nenhuma conta do WhatsApp conectada e ativa. |
| 503 | send_failed | Não foi possível enviar a mensagem; tente novamente em instantes. |
Limites de requisições
- Por número: 1 código a cada 60 segundos, 5 por hora e 10 por dia.
- Por chave de API: 60 envios por minuto.
- Por endereço IP: 120 requisições por minuto (incluindo a verificação).
- Verificação: 10 tentativas por minuto por número e no máximo 5 tentativas erradas por código.
- A cota mensal depende do seu plano; quando ela se esgota, é retornado
quota_exceeded. Chaves de teste não consomem cota.
Aquecimento da conta e limite diário
- Números WhatsApp recém-conectados passam por aquecimento para reduzir o risco de banimento: 30 códigos por dia nos primeiros 3 dias, 100 por dia nos dias 4 a 7 e, depois, 500 por dia por conta (valores padrão).
- Uma conta que atinge o limite diário é ignorada e os códigos são enviados pelas suas outras contas conectadas. Se todas estiverem no limite, é retornado
429 daily_limit_reached; o contador é zerado à meia-noite, no horário de Istambul. - Para mais volume, escolha um pacote com várias contas. As chaves de teste não são afetadas por esses limites.
Chaves de teste
Chaves que começam com wfo_test_ não enviam mensagem de WhatsApp e não consomem cota; o código é retornado no campo test_code. As regras de envio e de limite são as mesmas da chave de produção, e uma assinatura ativa continua sendo necessária. Para passar para produção, basta trocar a chave.
{ "success": true, "request_id": "req_...", "status": "sent", "test_code": "482913" }
Formato do número de telefone
- O número é reduzido a dígitos (+, espaços e traços são removidos) e deve ter de 10 a 15 dígitos.
- Inclua o código do país (ex.:
905321234567). Um número de 11 dígitos começando com 0 é tratado como turco e recebe o 90 no início. - Um número inválido retorna
422 invalid_phone.
Notas de segurança
- Os códigos são gerados com um gerador aleatório criptograficamente seguro e nunca são armazenados em texto puro.
- Nunca use a chave de API em navegadores, aplicativos móveis ou código público; faça as chamadas a partir do seu servidor.
- Confirme sempre o código no servidor com
/verify. - O WapFlow OTP não é a API oficial do WhatsApp e não garante a entrega; mantenha um canal de backup para ações críticas.
Plugin WordPress
- Baixe o wapflow-otp.zip.
- No painel administrativo do WordPress, vá em Plugins → Adicionar novo → Enviar plugin, envie o arquivo zip e ative-o.
- Nas configurações do plugin, cole a chave de API que você criou no painel do WapFlow.
- Use o botão "Testar conexão" para verificar a chave e o seu plano.
- Teste primeiro com uma chave de teste e depois troque pela chave de produção.