Enviar WhatsApp com Kotlin: exemplo de API REST (OkHttp e Android)
Para enviar WhatsApp com Kotlin você faz um POST com OkHttp em /api/v1/{instanceId}/send/text, com os cabeçalhos x-api-key e x-api-secret e um JSON com number e text. Vale para backend (Ktor, Spring) e para testes. No Android, a regra é outra: o app nunca deve guardar a chave e o segredo, porque qualquer um consegue extrair strings de um APK. O app chama o seu backend, e o backend chama o ZapZap.
Publicado em · 3 min de leitura
O que você precisa antes de começar
Conta no ZapZap, instância conectada por QR code, chave e segredo da API e o ID da instância. A autenticação usa x-api-key e x-api-secret. Adicione okhttp ao build.gradle.kts (com.squareup.okhttp3:okhttp).
Valide a instância com cURL antes de codar.
cURL
curl -X POST https://api.zapzapapi.com/api/v1/SEU_INSTANCE_ID/send/text \
-H "Content-Type: application/json" \
-H "x-api-key: SUA_API_KEY" \
-H "x-api-secret: SEU_API_SECRET" \
-d '{"number":"5511999999999","text":"Olá! Teste de envio pela API."}'Como enviar uma mensagem de texto com Kotlin e OkHttp
A classe abaixo cria um OkHttpClient único, com timeouts, e envia o JSON. Em Android, chamadas de rede não podem rodar na thread principal; aqui o método é suspend e usa Dispatchers.IO.
Para montar JSON com segurança, use kotlinx.serialization ou org.json em vez de concatenar texto. O exemplo usa org.json.JSONObject para evitar erro de escape.
Kotlin
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import java.util.concurrent.TimeUnit
class ZapZapClient(
private val instancia: String,
private val key: String,
private val secret: String,
) {
private val http = OkHttpClient.Builder()
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
private val json = "application/json".toMediaType()
suspend fun enviarTexto(numero: String, texto: String): String = post(
"/send/text",
JSONObject().put("number", numero).put("text", texto),
)
private suspend fun post(caminho: String, corpo: JSONObject): String =
withContext(Dispatchers.IO) {
val req = Request.Builder()
.url("https://api.zapzapapi.com/api/v1/" + instancia + caminho)
.header("x-api-key", key)
.header("x-api-secret", secret)
.post(corpo.toString().toRequestBody(json))
.build()
http.newCall(req).execute().use { r ->
val texto = r.body?.string().orEmpty()
check(r.isSuccessful) { "ZapZap " + r.code + ": " + texto }
texto
}
}
}Como enviar imagem, PDF e áudio com Kotlin
A rota é /send/media. O campo type escolhe o tipo (image, video, audio, ptt, document, sticker e outros), file é a URL pública, text a legenda e docName o nome do documento.
Kotlin
// dentro de ZapZapClient
suspend fun enviarPdf(numero: String, url: String, nome: String, legenda: String = ""): String = post(
"/send/media",
JSONObject()
.put("number", numero)
.put("type", "document")
.put("file", url)
.put("docName", nome)
.put("text", legenda),
)Por que o app Android deve chamar o seu backend
Tudo que vai dentro de um APK pode ser extraído. Se a chave e o segredo da API estiverem no app, qualquer pessoa pode enviar mensagens pelo seu número. O desenho seguro é: o app chama uma rota sua, autenticada com o login do usuário, e o seu servidor chama o ZapZap com as credenciais guardadas lá.
O backend abaixo, em Ktor, expõe POST /avisos e repassa para o ZapZap. Ele também é o lugar certo para aplicar regras suas: quem pode enviar, limite por usuário e registro do envio.
Kotlin (Ktor)
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.*
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.routing.*
data class Aviso(val numero: String, val texto: String)
fun Application.rotas(zap: ZapZapClient) {
routing {
post("/avisos") {
// aqui: autentique o usuário do app e aplique limites seus
val aviso = call.receive<Aviso>()
val resposta = runCatching { zap.enviarTexto(aviso.numero, aviso.texto) }
resposta.onSuccess { call.respond(HttpStatusCode.Accepted, it) }
.onFailure { call.respond(HttpStatusCode.BadGateway, "falha no envio") }
}
}
}Como receber as respostas e o que conferir antes de produção
Receber mensagens é sempre no servidor: configure a URL em configurar webhook, ligue o evento messages e trate data.message (text, chatid, fromMe), ignorando fromMe verdadeiro. Para avisar o app, use push (FCM) a partir do seu servidor. Assinatura e deduplicação estão no guia de webhook em produção.
Checklist: credenciais só no servidor; timeouts; checagem de status; retry só em 429 e 5xx; limite por usuário; e envio só para quem aceitou receber. Outras linguagens: Java, Node.js, Python. Endpoints completos na referência da API.
Resumo rápido
- OkHttp com corrotinas e Dispatchers.IO resolve o envio; nunca na thread principal.
- A chave e o segredo da API nunca vão dentro do app: tudo que está no APK pode ser extraído.
- O app chama o seu backend, e o backend chama o ZapZap.
- Receber mensagens é no servidor, por webhook, e o app é avisado por push.
Continue lendo
Perguntas frequentes
Posso chamar a API direto do app Android?
Tecnicamente sim, mas não deve. A chave e o segredo ficariam dentro do APK e podem ser extraídos. Chame o seu backend, que guarda as credenciais.
Funciona com Retrofit ou Ktor Client?
Sim. A API é REST: os mesmos cabeçalhos e o mesmo JSON valem em qualquer cliente HTTP.
E Swift ou iOS?
Vale a mesma regra: o app chama o seu backend. No servidor, qualquer linguagem desta série serve, e o app só precisa de uma rota sua.
Usar a API não oficial pode levar a bloqueio do número?
Pode. Uma API não oficial viola os termos do WhatsApp e o número pode ser limitado ou bloqueado. Opt-in, ritmo humano, aquecimento e lista limpa reduzem o risco, sem garantia. Para canal homologado, use a API oficial da Meta.
Teste o Kotlin na sua instância
Crie a conta, conecte um número e envie a primeira mensagem. R$15 por número ativo ao mês, sem cobrança por mensagem.
