---
title: "Lua SDK"
lang: en
canonical: https://doc.apibrasil.io/sdks/lua
markdown: https://doc.apibrasil.io/sdks/lua.md
source: apibrasil-documentation
---

# Lua SDK

- **Status:** published
- **Install:** `luarocks install apibrasil`
- **Registry:** LuaRocks — https://luarocks.org/modules/jhowbhz/apibrasil
- **Repository:** https://github.com/APIBrasil/apigratis-sdk-lua

## Do not make up the signature

DO NOT INVENT THE Lua SDK's API. Every library in this catalogue has its own constructor, method names and return shape, and none of them can be deduced from the package name. Open the README of the repository above and use exactly what is written there. If you cannot open the repository, DO NOT GUESS: write the client in plain HTTP, following the section below, and say in your answer that this is what you did and why.

## How to authenticate

The Bearer goes in the Authorization header, on every call. The DeviceToken only on plan-billed APIs — credit-billed ones don't ask for it. It's the same pair the SDK sets for you.

With homolog set to true in the body, the gateway answers from a fixed dataset. The document number 00000000000 belongs to that dataset and to no one.

## The repository on GitHub

- **Stars:** 0
- **Forks:** 0
- **Open issues:** 0
- **Language:** Lua
- **Licence:** MIT License
- **Last push:** July 28, 2026
- **git clone:** `https://github.com/APIBrasil/apigratis-sdk-lua.git`

## Repository README

Reproduced from the repository, on the default branch. It is the documentation written by whoever maintains the library: the SDK's signature is what is written here, not what is deduced from the package name.

# SDK LUA - APIGratis by API BRASIL 💧

SDK oficial Lua da plataforma [APIBrasil](https://apibrasil.com.br) — WhatsApp, SMS, consultas de CPF/CNPJ, veículos, CEP, correios, pagamentos PIX/boleto e muito mais.

[![LuaRocks](https://img.shields.io/luarocks/v/jhowbhz/apibrasil)](https://luarocks.org/modules/jhowbhz/apibrasil)
[![CI](https://github.com/APIBrasil/apigratis-sdk-lua/actions/workflows/ci.yml/badge.svg)](https://github.com/APIBrasil/apigratis-sdk-lua/actions/workflows/ci.yml)
<a href="https://github.com/APIBrasil/apigratis-sdk-lua/issues" target="_blank"><img alt="GitHub issues" src="https://img.shields.io/github/issues/APIBrasil/apigratis-sdk-lua"></a>
<a href="https://github.com/APIBrasil/apigratis-sdk-lua/network" target="_blank"><img alt="GitHub forks" src="https://img.shields.io/github/forks/APIBrasil/apigratis-sdk-lua"></a>
<a href="https://github.com/APIBrasil/apigratis-sdk-lua/stargazers" target="_blank"><img alt="GitHub stars" src="https://img.shields.io/github/stars/APIBrasil/apigratis-sdk-lua"></a>

## Canais de suporte (Comunidade)

[![WhatsApp Group](https://img.shields.io/badge/WhatsApp-Channel-25D366?logo=whatsapp)](https://whatsapp.com/channel/0029VaMiaT6B4hdX3hrUcz3X)
[![Telegram Group](https://img.shields.io/badge/Telegram-Group-32AFED?logo=telegram)](https://t.me/apibrasil1)

## Instalação

```bash
luarocks install apibrasil
```

Requer **Lua >= 5.1** — funciona em Lua 5.1/5.2/5.3/5.4, LuaJIT e OpenResty.

O codec JSON acompanha a SDK, sem dependência externa. Para o HTTP, o rockspec instala `luasocket` + `luasec`; a SDK também aceita `lua-http`, `resty.http` (OpenResty) e o `curl` da máquina — veja [Transporte plugável](#transporte-plugável).

Obtenha suas credenciais em https://apibrasil.com.br

## Começando

```lua
local apibrasil = require("apibrasil")

local client = apibrasil.new({
  bearer_token = "SEU_BEARER_TOKEN",
  device_token = "SEU_DEVICE_TOKEN",
})

-- WhatsApp
local envelope, err = client.whatsapp:send_text({
  number = "5511999999999",
  text = "Olá! 👋",
})

-- Consulta CNPJ (por créditos)
local empresa = client.consulta:cnpj({ cnpj = "00000000000000" })
print(empresa.balance, empresa.data)
```

O `bearer_token` é o JWT do login; o `device_token` é o device dos serviços device-based.

As credenciais também podem vir só do ambiente — `apibrasil.from_env()` lê automaticamente `APIBRASIL_BEARER_TOKEN`, `APIBRASIL_DEVICE_TOKEN`, `APIBRASIL_SECRET_KEY` e `APIBRASIL_BASE_URL`.

Também é possível autenticar por email/senha — `apibrasil.login` devolve o cliente já autenticado, junto da sessão:

```lua
local client, session = apibrasil.login({
  email = "voce@empresa.com.br",
  password = "******",
})
```

Contas com 2FA concluem o login em três passos, aplicando o token com `client.auth:authenticate`:

```lua
local client = apibrasil.from_env()
local session = client.auth:login({ email = email, password = senha })

if client.auth.requires_2fa(session) then
  client.auth:send_2fa({ challenge = session.challenge, method = "email" })
  session = client.auth:verify_2fa({ challenge = session.challenge, code = "000000" })
end

client = client.auth:authenticate(session)
```

## Como a plataforma funciona

A API Brasil tem duas famílias de serviços:

| Família          | Autenticação                                   | Exemplos                                                                     |
| ---------------- | ---------------------------------------------- | ---------------------------------------------------------------------------- |
| **Device-based** | `Authorization: Bearer` + header `DeviceToken` | WhatsApp, SMS, veículos, CEP, correios, DDD, feriados, tradução, clima, OCR  |
| **Por créditos** | apenas `Authorization: Bearer` (debita saldo)  | `client.consulta`: `cpf`, `cnpj`, `veiculos`, Serasa, CNH                    |

Para os serviços device-based, crie um device com a `SecretKey` da API desejada (painel APIBrasil) e use o `device_token` retornado:

```lua
local device = client
  :with_options({ secret_key = "SUA_SECRET_KEY" })
  .devices:store({ device_name = "meu-bot", type = "server" })

client = client:with_device(device.device_token)
```

O cliente é um valor imutável: `with_device`, `with_bearer_token`, `with_secret_key`, `with_options` e `with_strict` devolvem sempre um **novo** cliente.

## Serviços disponíveis

Cada serviço é um campo do cliente, criado sob demanda:

| Campo                                            | Descrição                                                                                              |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| `client.whatsapp`                                | WhatsApp: `start`, `qrcode`, `send_text`, `send_file`, `send_audio`, fila (`queue`)...                 |
| `client.evolution`                               | Evolution API: `request(controller, action, body)`, `call(path, body)`, `queue(...)`                   |
| `client.whatsmeow`                               | WhatsMeow: `send_text`, `instance_create`, `instance_qr`, `request(action, body)`                      |
| `client.sms`                                     | SMS device-based (`send`) e por créditos (`send_with_credits`)                                         |
| `client.dados`                                   | Dados cadastrais device-based (`cpf`, `cnpj`, `lista_socios`...)                                       |
| `client.vehicles`                                | Veículos por placa (`dados`, `fipe`, `base_dados`, `base_fipe`)                                        |
| `client.fipe`                                    | Tabela FIPE (`consultar_marcas`, `consultar_modelos`...)                                               |
| `client.correios`                                | Correios (`rastreio`, `request`)                                                                       |
| `client.cep`                                     | CEP + geolocalização (`cep`, `cidades`, `estados`, `calcular_distancia`)                               |
| `client.geolocation` / `client.geomatrix`        | Geocoding e matriz de distâncias                                                                        |
| `client.recognize`                               | OCR / Google Vision (`base64`, `uri`)                                                                  |
| `client.ddd` / `client.holidays` / `client.translate` / `client.weather` | DDD, feriados, tradução, clima                                          |
| `client.loterias`                                | Loterias (`latest`, `resultado`)                                                                       |
| `client.database_ip`                             | GeoIP (`ip`)                                                                                           |
| `client.consulta`                                | Consultas por créditos: `cpf`, `cnpj`, `cnh`, `cep`, `veiculos`, `telefone`, `generic`                 |
| `client.ura` / `client.chip_virtual`             | URA reversa e chip virtual                                                                              |
| `client.bulk`                                    | Execução em lote (`direct`, `queue`)                                                                   |
| `client.auth`                                    | Login, 2FA, cadastro, recuperação de senha, perfil                                                     |
| `client.devices`                                 | CRUD de devices                                                                                        |
| `client.catalog`                                 | Catálogo de APIs, planos, documentações, servidores                                                    |
| `client.account`                                 | Saldo, faturas, notificações, tickets                                                                  |
| `client.payments`                                | Recargas e pagamentos PIX/boleto/cartão (Santander, Inter, Mercado Pago, Sicoob)                        |
| `client.ip_whitelist` / `client.bearer_rate_limit` | Segurança da conta                                                                                    |
| `client.reports`                                 | Relatórios e dashboard de consumo                                                                       |

Todo método recebe o body como tabela (ou `nil`) e termina com uma tabela de opções.

### WhatsApp

```lua
-- iniciar sessão e obter QR Code
client.whatsapp:start({ webhook_wh_message = "https://seu-webhook.com/mensagens" })

local qr = client.whatsapp:qrcode()
print(qr.response.qrcode) -- imagem do QR Code em base64

-- envios
client.whatsapp:send_text({ number = "5511999999999", text = "Olá!" })

client.whatsapp:send_file({
  number = "5511999999999",
  path = "https://exemplo.com/boleto.pdf",
})

client.whatsapp:send_location({
  number = "5511999999999",
  lat = -23.5,
  lng = -46.6,
})

-- qualquer action do catálogo
client.whatsapp:request("getAllChats")

-- fila assíncrona
client.whatsapp:queue("sendText", { number = "5511999999999", text = "por fila" })
```

O envelope device-based **é** o próprio JSON: os campos são lidos direto, e os poucos auxiliares têm nomes que não colidem com chaves da API.

```lua
local envelope = client.whatsapp:send_text({ number = numero, text = "Olá!" })

envelope.error       -- false
envelope.message     -- mensagem do gateway
envelope.response    -- payload do provedor
envelope.api_limit   -- limite do plano

envelope:is_error()            -- false
envelope:get("response.id")    -- acesso por caminho
envelope:raw()                 -- a tabela completa
```

### Consultas por créditos

```lua
local Consulta = require("apibrasil").Consulta

local cpf = client.consulta:cpf({ cpf = "00000000000" })
print(cpf.balance, cpf.data)

-- o campo `tipo` define o produto consultado — use o builder
client.consulta:cnpj(
  Consulta.new("lista-socios"):field("cnpj", "00000000000000")
)

-- modo homologação (sandbox, sem cobrança)
client.consulta:cnpj(
  Consulta.new("serasa-score-pj")
    :homolog()
    :field("cnpj", "00000000000000")
)

-- qualquer serviço do catálogo, e os créditos disponíveis
client.consulta:generic("cnh", { cpf = "00000000000" })
client.consulta:credits("cpf")
```

O builder também aceita `:lite()`, `:agrupados({...})`, `:extra({...})` e `:fields({...})`; qualquer método de serviço recebe o builder diretamente no lugar da tabela.

### Veículos e FIPE (device-based)

```lua
client.vehicles:dados({ placa = "ABC1234" })
client.vehicles:fipe({ placa = "ABC1234" })
client.fipe:consultar_marcas({ codigoTabelaReferencia = 300 })
```

### SMS

```lua
client.sms:send({ number = "5511999999999", message = "Olá!" })
client.sms:send_with_credits({ number = "5511999999999", message = "Olá!" })
```

### Pagamentos e recargas

```lua
local Payments = require("apibrasil.platform.payments")

client.payments:recharge({ amount = 50, type = "pix" })
client.payments:pix_generate(Payments.SANTANDER, { amount = 50 })
client.payments:pix_status("santander", "TX_ID")

-- bytes crus do PDF
local pdf = client.payments:boleto_pdf(Payments.INTER, "ID")
local file = assert(io.open("boleto.pdf", "wb"))
file:write(pdf)
file:close()
```

### Múltiplos devices

```lua
local bot1 = client:with_device("device_token_1")
local bot2 = client:with_device("device_token_2")

bot1.whatsapp:send_text({ number = numero, text = "do bot 1" })
bot2.whatsapp:send_text({ number = numero, text = "do bot 2" })
```

## Tratamento de erros

Toda chamada devolve `resultado` ou `nil, erro`; a falha carrega a categoria em `kind`:

| `kind`                  | Quando                                          |
| ----------------------- | ----------------------------------------------- |
| `validation`            | 400/422 — payload inválido                      |
| `authentication`        | 401 — token ausente/expirado                    |
| `insufficient_balance`  | 402 — sem saldo/créditos                        |
| `permission`            | 403 — sem permissão (ex: exige PJ)              |
| `not_found`             | 404/410 — sem dados / rota desativada           |
| `rate_limit`            | 429 — limite atingido (`retry_after`, em ms)    |
| `server`                | 5xx — erro do gateway/provedor                  |
| `network` / `timeout`   | falha antes da resposta                         |
| `api`                   | qualquer outra falha da API                     |

```lua
local consulta, err = client.consulta:cpf({ cpf = "00000000000" })

if err then
  if err:is_insufficient_balance() then
    print("Recarregue seus créditos")
  elseif err:is_rate_limit() then
    print("Aguarde " .. err.retry_after .. "ms")
  else
    -- mensagem já formatada com status e código
    print(tostring(err), err.status, err.code)
  end
else
  print(consulta.data)
end
```

Cada categoria tem o seu predicado: `err:is_insufficient_balance()`, `err:is_rate_limit()`, `err:is_network()`... e `apibrasil.Error.is(valor)` reconhece um erro da SDK.

## Modo estrito

`client:with_strict()` devolve um cliente que **levanta** a falha em vez de devolvê-la — o par natural do `pcall` de Lua, útil em scripts e pipelines:

```lua
local client = apibrasil.from_env():with_strict()

local envelope = client.whatsapp:send_text({ number = numero, text = "Olá!" })
print(envelope.response)

local ok, err = pcall(function()
  return client.account:balance()
end)

if not ok then
  print(tostring(err), err.kind)
end
```

Para um trecho isolado, sem trocar de cliente, use `apibrasil.unwrap`:

```lua
local envelope = apibrasil.unwrap(client.whatsapp:send_text(body))
```

## Retry e observabilidade

Por padrão a SDK refaz a chamada em **HTTP 429** e em **falhas de conexão** (2 tentativas extras, backoff exponencial com jitter, respeitando `Retry-After`). Timeouts e erros de negócio nunca são refeitos — evita duplicar cobranças e envios.

```lua
local client = apibrasil.new({
  retry = {
    retries = 3,
    min_delay = 500,
    max_delay = 5000,
    retry_on_statuses = { 429, 503 },
  },
  hooks = {
    request = function(info)
      print("→ " .. info.method .. " " .. info.url .. " (#" .. info.attempt .. ")")
    end,
    response = function(info)
      print("← " .. info.status .. " em " .. info.duration .. "ms")
    end,
    retry = function(info)
      print("retry em " .. info.delay .. "ms: " .. info.reason)
    end,
  },
})

-- ou desativando o retry
apibrasil.new({ retry = require("apibrasil.core.retry").none() })
```

Os hooks também podem ser um objeto com os métodos `on_request`, `on_response` e `on_retry`. Falhas dentro de um hook nunca derrubam a requisição.

Para limitar uma chamada, use `timeout` (em ms) — no cliente ou só naquela requisição:

```lua
client.whatsapp:send_text(body, { timeout = 10000 })
```

## Opções por requisição

`client:with_options` devolve um cliente que aplica as opções em todas as chamadas, mantendo base, credenciais e transporte:

```lua
client
  :with_options({
    secret_key = "SUA_SECRET_KEY",
    headers = { ["X-Correlation-Id"] = "abc-123" },
    timeout = 5000,
  })
  .devices:store({ device_name = "meu-bot" })

-- ou só nesta chamada — a tabela de opções é sempre o último argumento
client.whatsapp:send_text(body, { device_token = "outro-device" })
```

Opções aceitas: `query`, `headers`, `bearer_token`, `device_token`, `secret_key`, `timeout` e `response_type` (`"json"` ou `"binary"`).

## Transporte plugável

Lua não tem cliente HTTP na biblioteca padrão, então a SDK detecta o que existe no ambiente, nesta ordem:

1. `resty.http` — OpenResty (espera sem bloquear o worker);
2. `http.request` — [lua-http](https://github.com/daurnimator/lua-http);
3. `socket.http` + `ssl.https` — LuaSocket/LuaSec, **quando há um bundle de CAs**;
4. `curl` — a CLI da máquina, que usa o repositório de certificados do sistema.

A verificação de certificado é sempre ligada. Como o LuaSec não traz um repositório de CAs, a SDK procura o bundle nos caminhos usuais do sistema e em `SSL_CERT_FILE`; sem ele, prefere o `curl` a abrir mão da verificação.

```lua
local curl = require("apibrasil.core.transport.curl")
local luasocket = require("apibrasil.core.transport.luasocket")

apibrasil.new({ transport = curl.new({ proxy = "http://proxy:3128" }) })
apibrasil.new({ transport = luasocket.new({ ca_file = "/etc/ssl/cert.pem" }) })

-- qual transporte foi detectado
print(require("apibrasil.core.transport").default_name())
```

Um transporte é uma **função** `f(request) -> response, err` — o atalho para testes sem rede:

```lua
local transport = require("apibrasil.core.transport")

local client = apibrasil.new({
  bearer_token = "token-de-teste",
  device_token = "device-de-teste",
  transport = function(request)
    assert(request.url:find("/whatsapp/sendText$"))
    return transport.response_json(200, { error = false, response = { id = "ABC" } })
  end,
})

local envelope = client.whatsapp:send_text({ number = "5511999999999", text = "oi" })
assert(envelope.response.id == "ABC")
```

Também aceita uma **tabela** com o campo `request` — é assim que os transportes que acompanham a SDK são implementados.

## JSON: `null`, listas e objetos

Lua não distingue "tabela vazia" de "lista vazia", e `nil` não sobrevive dentro de uma tabela. O codec da SDK resolve as três coisas:

```lua
local apibrasil = require("apibrasil")

client.whatsapp:send_text({ text = apibrasil.null })   -- {"text":null}
client.ip_whitelist:set({})                            -- {"ip_whitelist":[]}
apibrasil.json.encode(apibrasil.array({}))             -- []
apibrasil.json.encode({})                              -- {}
```

Tabelas vazias sem marcação viram `{}` — o corpo das requisições da plataforma é sempre um objeto. Para usar um codec nativo (`cjson`, `dkjson`), troque com `apibrasil.json.use({ encode = ..., decode = ... })`.

## Catálogo gerado

As actions de WhatsApp/Evolution/WhatsMeow e os `tipo` das consultas são gerados do catálogo real da plataforma (`GET /documentations`):

```bash
lua scripts/codegen.lua
```

```lua
local catalog = require("apibrasil").catalog

catalog.service_actions("whatsapp")          -- todas as actions do WhatsApp
catalog.service_actions("cep")               -- { "bairros", "cep", "cidades", ... }
catalog.has_action("cep", "estados")         -- true
catalog.evolution_paths                      -- { "call/offer", "chat/deleteMessageForEveryone", ... }
catalog.consulta_servicos                    -- serviços de /consulta/{servico}/credits
catalog.consulta_tipo("acerta-essencial")    -- { service = "cpf", fields = { "cpf" } }
```

## Endpoint sem método dedicado?

Todo o gateway fica acessível pela porta de saída genérica, já com seus headers de autenticação:

```lua
client:request("post", "/consulta/cpf/credits", { cpf = "00000000000" })
client:request("get", "/reports/quick-stats")

-- corpo decodificado sem normalizar em objeto JSON (listas, texto)
local planos = client:execute("get", "/plans")

-- bytes crus (PDF de boleto, imagens)
local pdf = client:download("/inter/boleto/ID/pdf")
```

Documentação completa dos endpoints: https://doc.apibrasil.io

## Configuração avançada

```lua
local client = apibrasil.new({
  -- ou APIBRASIL_BEARER_TOKEN
  bearer_token = "...",
  -- ou APIBRASIL_DEVICE_TOKEN
  device_token = "...",
  -- usada em client.devices:store (ou APIBRASIL_SECRET_KEY)
  secret_key = "...",
  -- padrão (ou APIBRASIL_BASE_URL)
  base_url = "https://gateway.apibrasil.io/api/v2",
  timeout = 30000,
  headers = { ["X-Correlation-Id"] = "abc-123" },
  transport = require("apibrasil.core.transport.curl"),
  retry = { retries = 3 },
  hooks = { response = function(info) print(info.status) end },
  options = { timeout = 15000 },
  strict = false,
})
```

Os mesmos campos podem virar padrão da aplicação inteira:

```lua
apibrasil.configure({
  base_url = "https://gateway.apibrasil.io/api/v2",
  timeout = 60000,
})
```

A precedência é: `apibrasil.configure` < variáveis de ambiente < `apibrasil.new`. Credenciais vazias contam como ausentes: informar `""` é a forma de desligar o que veio do ambiente.

## Interface legada

`apibrasil.legacy` mantém o contrato das primeiras SDKs da plataforma — credenciais, body e action em uma única **string JSON** (`credentials` / `body` / `action`), com os erros da API devolvidos decodificados como resultado em vez de `nil, erro`.

```lua
local legacy = require("apibrasil").legacy.new()

local dados = [[{
  "action": "sendText",
  "credentials": {
    "DeviceToken": "SEU_DEVICE_TOKEN",
    "BearerToken": "SEU_BEARER_TOKEN"
  },
  "body": {"number": "5511999999999", "text": "Hello World for Lua"}
}]]

local resposta = legacy:whatsapp(dados)
```

Além de `whatsapp`, há `sms`, `cpf`, `cnpj` e `request(servico, dados)` (qualquer serviço).

Ela existe só para quem está migrando das SDKs PHP/Node com o formato antigo. Em código novo, prefira o cliente `apibrasil`, que cobre toda a plataforma com métodos dedicados, erros com categoria, retry e hooks.

## Desenvolvimento

```bash
luarocks install busted
luarocks install luacheck

busted                                        # testes (sem rede)
luacheck src spec examples scripts            # análise estática
lua scripts/check_rockspec.lua apibrasil-0.0.1-1.rockspec
```

`scripts/smoke.lua` carrega os 52 módulos e exercita o cliente **sem nenhuma
dependência** — é como o CI cobre LuaJIT e OpenResty, onde o `busted` não é
instalável (o manifesto do luarocks.org estoura o limite de 65536 constantes do
bytecode do Lua 5.1). Serve também como teste rápido depois de instalar:

```bash
lua scripts/smoke.lua
luajit scripts/smoke.lua
```

Os exemplos de `examples/` rodam direto do repositório:

```bash
export APIBRASIL_BEARER_TOKEN=...
export APIBRASIL_DEVICE_TOKEN=...

lua examples/basico.lua
lua examples/whatsapp.lua
```

## Publicando uma versão

A publicação é automática: criar a tag dispara o workflow `Release`, que
empacota o `.src.rock`, anexa ao release do GitHub e sobe para o
[luarocks.org](https://luarocks.org/modules/jhowbhz/apibrasil).

```bash
git tag v0.0.1
git push origin v0.0.1
```

Requisitos, uma vez só:

- o secret `LUAROCKS_API_KEY` no repositório (luarocks.org → *Settings* →
  *API keys*). Sem ele o release sai com o artefato anexado, mas o passo de
  publicação é pulado;
- `version` e `source.tag` do rockspec batendo com a tag — `check_rockspec.lua`
  falha o build antes de publicar caso divirjam.

Para publicar à mão, ou conferir o pacote antes da tag:

```bash
# a partir do fonte local, sem depender da tag ainda existir
luarocks make --tree=./lua_modules
luarocks pack --tree=./lua_modules apibrasil 0.0.1-1

# depois que a tag existe: gera o .src.rock e publica
luarocks pack apibrasil-0.0.1-1.rockspec
luarocks upload apibrasil-0.0.1-1.rockspec --api-key=SUA_CHAVE
```

O `luarocks pack` a partir do rockspec busca o fonte pela `source.url`, então
só funciona depois que a tag está no GitHub.

## Licença

MIT — veja [LICENSE](https://github.com/APIBrasil/apigratis-sdk-lua/blob/main/LICENSE).

## The same API over HTTP

Base URL: https://gateway.apibrasil.io/api/v2
Each endpoint's path and method are on that API's page in this documentation. Do not deduce a route from the service name.

### Authentication, as HTTP headers
- `Authorization: Bearer YOUR_TOKEN` — on every call.
- `DeviceToken: YOUR_DEVICE_TOKEN` — only on plan-billed APIs; credit-billed ones don't ask for it. The exact header name is whatever the endpoint's page declares.

```bash
curl -X POST https://gateway.apibrasil.io/api/v2/dados/cpf \
  -H "Authorization: Bearer $APIBRASIL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cpf": "00000000000", "homolog": true}'
```

With `homolog` set to true in the body, the gateway answers from a fixed dataset and spends no credit. The document number 00000000000 belongs to that dataset and to no one — use it in tests, never in production.

## The other languages

- [C++](https://doc.apibrasil.io/sdks/cpp.md): `git clone https://github.com/APIBrasil/apigratis-sdk-cpp`
- [Python](https://doc.apibrasil.io/sdks/python.md): `pip install api-brasil`
- [PHP](https://doc.apibrasil.io/sdks/php.md): `composer require jhowbhz/apigratis-sdk-php`
- [Java](https://doc.apibrasil.io/sdks/java.md): `mvn dependency:get -Dartifact=br.com.apibrasil:apigratis-sdk-java:0.0.1`
- [Ruby](https://doc.apibrasil.io/sdks/ruby.md): `gem install apigratis-sdk-ruby`
- [C# / .NET](https://doc.apibrasil.io/sdks/csharp.md): `dotnet add package ApiBrasil`
- [Node.js / TypeScript](https://doc.apibrasil.io/sdks/javascript.md): `npm install apigratis-sdk-nodejs`
- [Go](https://doc.apibrasil.io/sdks/go.md): `go get github.com/APIBrasil/apigratis-sdk-go`
- [Rust](https://doc.apibrasil.io/sdks/rust.md): `cargo add apibrasil`
- [Dart / Flutter](https://doc.apibrasil.io/sdks/flutter.md): `flutter pub add apigratis_sdk_flutter`
- [Elixir](https://doc.apibrasil.io/sdks/elixir.md): `mix deps.get  # com {:apibrasil, "~> 0.0.1"} no mix.exs`

## See also

- Official SDKs: [Official SDKs](https://doc.apibrasil.io/sdks.md)
- Documentation index: https://doc.apibrasil.io/llms.txt
- HTML version of this page: https://doc.apibrasil.io/sdks/lua
