Current section
Files
Jump to
Current section
Files
lib/api_brasil.ex
defmodule ApiBrasil do
@moduledoc """
SDK oficial Elixir da plataforma [APIBrasil](https://apibrasil.com.br) —
WhatsApp, SMS, consultas de CPF/CNPJ, veículos, CEP, correios, pagamentos
PIX/boleto e muito mais.
client =
ApiBrasil.new(
bearer_token: "SEU_BEARER_TOKEN",
device_token: "SEU_DEVICE_TOKEN"
)
# WhatsApp
{:ok, _envelope} =
ApiBrasil.Messaging.WhatsApp.send_text(client, %{
"number" => "5511999999999",
"text" => "Olá! 👋"
})
# Consulta CNPJ (por créditos)
{:ok, empresa} = ApiBrasil.Data.Consulta.cnpj(client, %{"cnpj" => "00000000000000"})
ApiBrasil.Core.CreditResponse.data(empresa)
Credenciais não informadas são lidas das variáveis de ambiente
`APIBRASIL_BEARER_TOKEN`, `APIBRASIL_DEVICE_TOKEN`, `APIBRASIL_SECRET_KEY`
e `APIBRASIL_BASE_URL` — basta `from_env/0`.
## Como a plataforma funciona
| Família | Autenticação | Exemplos |
| ---------------- | ---------------------------------------------- | ------------------------------------------------------------ |
| **Device-based** | `Authorization: Bearer` + header `DeviceToken` | WhatsApp, SMS, veículos, CEP, correios, DDD, clima, OCR |
| **Por créditos** | apenas `Authorization: Bearer` (debita saldo) | `ApiBrasil.Data.Consulta`: CPF, CNPJ, veículos, Serasa, CNH |
## Convenções
- toda função devolve `{:ok, resultado}` ou `{:error, %ApiBrasil.Core.Error{}}`;
- toda função tem uma variante `!` que devolve o resultado direto e levanta
em caso de falha;
- todas aceitam uma keyword list final com as opções da requisição
(`:query`, `:headers`, `:bearer_token`, `:device_token`, `:secret_key`,
`:timeout`, `:response_type`) — veja `ApiBrasil.Core.HTTP`;
- o cliente é um valor imutável: `put_bearer_token/2` e `with_device/2`
devolvem um **novo** cliente.
## Serviços
| Módulo | Descrição |
| ------------------------------------- | ----------------------------------------------------------------- |
| `ApiBrasil.Messaging.WhatsApp` | WhatsApp: `start`, `qrcode`, `send_text`, `send_file`, fila... |
| `ApiBrasil.Messaging.Evolution` | Evolution API (`/evolution/{controller}/{action}`) |
| `ApiBrasil.Messaging.WhatsMeow` | WhatsMeow (`/whatsmeow/{action}`) |
| `ApiBrasil.Messaging.SMS` | SMS device-based e por créditos |
| `ApiBrasil.Data.Dados` | Dados cadastrais device-based (CPF, CNPJ, sócios...) |
| `ApiBrasil.Data.Vehicles` | Veículos por placa |
| `ApiBrasil.Data.Fipe` | Tabela FIPE |
| `ApiBrasil.Data.Correios` | Correios |
| `ApiBrasil.Data.Cep` | CEP + geolocalização |
| `ApiBrasil.Data.Geolocation` | Geocoding |
| `ApiBrasil.Data.Geomatrix` | Matriz de distâncias |
| `ApiBrasil.Data.Recognize` | OCR / Google Vision |
| `ApiBrasil.Data.Ddd` | DDD |
| `ApiBrasil.Data.Holidays` | Feriados |
| `ApiBrasil.Data.Translate` | Tradução |
| `ApiBrasil.Data.Weather` | Clima |
| `ApiBrasil.Data.Loterias` | Loterias |
| `ApiBrasil.Data.DatabaseIp` | GeoIP |
| `ApiBrasil.Data.Consulta` | Consultas por crédito (CPF, CNPJ, CNH, veículos, Serasa...) |
| `ApiBrasil.Data.Ura` | URA reversa / ligações |
| `ApiBrasil.Data.ChipVirtual` | Chip virtual |
| `ApiBrasil.Data.Bulk` | Execução em lote |
| `ApiBrasil.Platform.Auth` | Login, 2FA, cadastro, recuperação de senha, perfil |
| `ApiBrasil.Platform.Devices` | CRUD de devices |
| `ApiBrasil.Platform.Catalog` | Catálogo de APIs, planos, documentações, servidores |
| `ApiBrasil.Platform.Account` | Saldo, faturas, notificações, tickets |
| `ApiBrasil.Platform.Payments` | Recargas e pagamentos PIX/boleto/cartão |
| `ApiBrasil.Platform.IpWhitelist` | Whitelist de IPs da conta |
| `ApiBrasil.Platform.BearerRateLimit` | Rate limit por Bearer Token |
| `ApiBrasil.Platform.Reports` | Relatórios e dashboard de consumo |
"""
alias ApiBrasil.Client
alias ApiBrasil.Core.{Config, Error, HTTP, Service, Transport}
alias ApiBrasil.Platform.Auth
@doc """
Cria o cliente. Campos não informados vêm do ambiente e da configuração da
aplicação.
ApiBrasil.new(bearer_token: "jwt", device_token: "device")
ApiBrasil.new(
base_url: "https://gateway.apibrasil.io/api/v2",
timeout: 60_000,
headers: %{"X-Correlation-Id" => "abc-123"},
retry: %ApiBrasil.Core.Retry{retries: 3},
hooks: %{response: &IO.inspect/1}
)
Veja `ApiBrasil.Core.Config` para a lista completa de opções.
"""
@spec new(keyword() | map() | Config.t()) :: Client.t()
def new(config \\ []), do: Config.resolve(config)
@doc "Cria o cliente apenas com as credenciais do ambiente."
@spec from_env() :: Client.t()
def from_env, do: new([])
@doc "Configuração atual do cliente."
@spec config(Client.t()) :: Config.t()
def config(%Client{} = client), do: Config.from_client(client)
@doc """
Devolve um cliente que aplica `opts` em todas as chamadas — mesma base,
mesmas credenciais.
client
|> ApiBrasil.with_options(secret_key: "SUA_SECRET_KEY")
|> ApiBrasil.Platform.Devices.store(%{"device_name" => "meu-bot"})
"""
@spec with_options(Client.t(), keyword()) :: Client.t()
def with_options(%Client{} = client, opts) do
%{client | options: HTTP.merge_options(client.options, opts)}
end
@doc "Define/atualiza o Bearer Token, devolvendo um novo cliente."
@spec put_bearer_token(Client.t(), String.t() | nil) :: Client.t()
def put_bearer_token(%Client{} = client, token),
do: %{client | bearer_token: presence(token)}
@doc "Define/atualiza o DeviceToken, devolvendo um novo cliente."
@spec put_device_token(Client.t(), String.t() | nil) :: Client.t()
def put_device_token(%Client{} = client, token),
do: %{client | device_token: presence(token)}
@doc "Define/atualiza a SecretKey, devolvendo um novo cliente."
@spec put_secret_key(Client.t(), String.t() | nil) :: Client.t()
def put_secret_key(%Client{} = client, key), do: %{client | secret_key: presence(key)}
@doc """
Devolve um novo cliente com as mesmas credenciais, mas apontando para outro
device — útil para gerenciar vários números/instâncias.
bot1 = ApiBrasil.with_device(client, "device_token_1")
bot2 = ApiBrasil.with_device(client, "device_token_2")
ApiBrasil.Messaging.WhatsApp.send_text(bot1, %{"number" => n, "text" => "do bot 1"})
ApiBrasil.Messaging.WhatsApp.send_text(bot2, %{"number" => n, "text" => "do bot 2"})
"""
@spec with_device(Client.t(), String.t()) :: Client.t()
def with_device(%Client{} = client, device_token), do: put_device_token(client, device_token)
@doc "Monta a URL completa de um caminho do gateway."
@spec url(Client.t(), String.t()) :: String.t()
def url(%Client{} = client, path), do: HTTP.url(client, path)
@doc """
Porta de saída genérica: chama qualquer endpoint do gateway com os headers
de autenticação já configurados. Use para rotas que ainda não têm função
dedicada na SDK.
ApiBrasil.request(client, :post, "/consulta/cpf/credits", %{"cpf" => "00000000000"})
ApiBrasil.request(client, :get, "/reports/quick-stats")
"""
@spec request(Client.t(), Transport.method(), String.t(), term(), keyword()) ::
{:ok, map()} | {:error, Error.t()}
def request(%Client{} = client, method, path, body \\ nil, opts \\ []),
do: HTTP.request_json(client, method, path, body, opts)
@doc "Como `request/5`, mas levanta `ApiBrasil.Core.Error` em caso de falha."
@spec request!(Client.t(), Transport.method(), String.t(), term(), keyword()) :: map()
def request!(%Client{} = client, method, path, body \\ nil, opts \\ []),
do: Service.unwrap!(request(client, method, path, body, opts))
@doc """
Como `request/5`, mas devolve o corpo decodificado sem normalizar em objeto
JSON (útil quando a rota responde uma lista, texto ou bytes).
"""
@spec execute(Client.t(), Transport.method(), String.t(), term(), keyword()) ::
{:ok, term()} | {:error, Error.t()}
def execute(%Client{} = client, method, path, body \\ nil, opts \\ []),
do: HTTP.execute(client, method, path, body, opts)
@doc "Baixa os bytes crus de uma rota (PDF de boleto, imagens...)."
@spec download(Client.t(), String.t(), keyword()) :: {:ok, binary()} | {:error, Error.t()}
def download(%Client{} = client, path, opts \\ []),
do: HTTP.bytes(client, :get, path, nil, opts)
@doc """
Autentica por email/senha e devolve um cliente já autenticado, junto da
sessão retornada pela plataforma.
{:ok, client, sessao} =
ApiBrasil.login(%{"email" => "voce@empresa.com.br", "password" => "******"})
Devolve erro quando a conta exige 2FA — nesse caso use
`ApiBrasil.Platform.Auth.login/3` + `ApiBrasil.Platform.Auth.send_2fa/3` +
`ApiBrasil.Platform.Auth.verify_2fa/3`.
"""
@spec login(map() | keyword(), keyword() | map() | Config.t()) ::
{:ok, Client.t(), map()} | {:error, Error.t()}
def login(credentials, config \\ []) do
client = new(config)
with {:ok, session} <- Auth.login(client, credentials) do
if Auth.requires_2fa?(session) do
{:error,
Error.authentication(
"Esta conta exige autenticação em dois fatores. " <>
"Use ApiBrasil.Platform.Auth.login/3 + send_2fa/3 + verify_2fa/3.",
response: session
)}
else
{:ok, Auth.authenticate(client, session), session}
end
end
end
@doc "Como `login/2`, mas levanta `ApiBrasil.Core.Error` em caso de falha."
@spec login!(map() | keyword(), keyword() | map() | Config.t()) :: {Client.t(), map()}
def login!(credentials, config \\ []) do
case login(credentials, config) do
{:ok, client, session} -> {client, session}
{:error, error} -> raise error
end
end
defp presence(nil), do: nil
defp presence(""), do: nil
defp presence(token), do: token
end