Dev

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

Este artigo também está disponível em: English · Español

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.

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.