---
title: "SDK Scala"
lang: pt-BR
canonical: https://doc.apibrasil.io/sdks/scala
markdown: https://doc.apibrasil.io/sdks/scala.md
source: apibrasil-documentation
---

# SDK Scala

- **Situação:** código público, ainda sem pacote
- **Instalação:** Este SDK ainda não foi publicado em registry nenhum: não há comando de instalação. O código está no repositório abaixo.
- **Repositório:** https://github.com/APIBrasil/apigratis-sdk-scala

## Não invente a assinatura

NÃO INVENTE A API DO SDK DE Scala. Cada biblioteca deste catálogo tem construtor, nomes de método e formato de retorno próprios, e nenhum deles se deduz do nome do pacote. Abra o README do repositório acima e use exatamente o que está escrito lá. Se você não conseguir abrir o repositório, NÃO CHUTE: escreva o cliente em HTTP puro, seguindo a seção abaixo, e diga na resposta que foi isso que você fez e por quê.

## Como autenticar

O Bearer vai no cabeçalho Authorization, em toda chamada. O DeviceToken só nas APIs cobradas por plano — as por crédito não pedem. É o mesmo par que o SDK põe por você.

Com homolog verdadeiro no corpo, o gateway responde de uma base fixa. O CPF 00000000000 é o dela e não é de ninguém.

## O repositório no GitHub

- **Estrelas:** 0
- **Forks:** 0
- **Issues abertas:** 0
- **Linguagem:** Scala
- **Licença:** MIT License
- **Último envio:** 28 de julho de 2026
- **git clone:** `https://github.com/APIBrasil/apigratis-sdk-scala.git`

## README do repositório

Reproduzido do repositório, no ramo padrão. É a documentação de quem mantém a biblioteca: a assinatura do SDK é o que está aqui, e não o que se deduz do nome do pacote.

# SDK SCALA - APIGratis by API BRASIL 💧

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

[![Maven Central](https://img.shields.io/maven-central/v/br.com.apibrasil/apigratis-sdk-scala_3.svg)](https://central.sonatype.com/artifact/br.com.apibrasil/apigratis-sdk-scala_3)
[![CI](https://github.com/APIBrasil/apigratis-sdk-scala/actions/workflows/ci.yml/badge.svg)](https://github.com/APIBrasil/apigratis-sdk-scala/actions/workflows/ci.yml)
<a href="https://github.com/APIBrasil/apigratis-sdk-scala/issues" target="_blank"><img alt="GitHub issues" src="https://img.shields.io/github/issues/APIBrasil/apigratis-sdk-scala"></a>
<a href="https://github.com/APIBrasil/apigratis-sdk-scala/network" target="_blank"><img alt="GitHub forks" src="https://img.shields.io/github/forks/APIBrasil/apigratis-sdk-scala"></a>
<a href="https://github.com/APIBrasil/apigratis-sdk-scala/stargazers" target="_blank"><img alt="GitHub stars" src="https://img.shields.io/github/stars/APIBrasil/apigratis-sdk-scala"></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

```scala
// build.sbt
libraryDependencies += "br.com.apibrasil" %% "apigratis-sdk-scala" % "0.0.1"
```

```scala
// scala-cli
//> using dep br.com.apibrasil::apigratis-sdk-scala:0.0.1
```

```xml
<!-- Maven (Scala 3) -->
<dependency>
  <groupId>br.com.apibrasil</groupId>
  <artifactId>apigratis-sdk-scala_3</artifactId>
  <version>0.0.1</version>
</dependency>
```

Publicada para **Scala 2.13** e **Scala 3.3+**, sobre **JDK 11 ou superior**. **Não tem nenhuma dependência de runtime**: o HTTP usa o `java.net.http.HttpClient` do próprio JDK e o JSON usa o codec da SDK — nada de conflito com circe, play-json, jsoniter ou o que você já usa.

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

## Começando

```scala
import br.com.apibrasil.sdk._
import br.com.apibrasil.sdk.core.Json

val api = ApiBrasil(
  bearerToken = Some("SEU_BEARER_TOKEN"),
  deviceToken = Some("SEU_DEVICE_TOKEN")
)

// WhatsApp
api.whatsapp.sendText(Json.obj("number" -> "5511999999999", "text" -> "Olá! 👋"))

// Consulta CNPJ (por créditos)
val empresa = api.consulta.cnpj(Json.obj("cnpj" -> "00000000000000")).orThrow
println(empresa.data)
```

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

As credenciais também podem vir só do ambiente — `ApiBrasil.fromEnv` 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:

```scala
val resultado = ApiBrasil.login(
  Json.obj("email" -> "voce@empresa.com.br", "password" -> "******")
).orThrow

val api = resultado.api
```

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

```scala
import br.com.apibrasil.sdk.platform.AuthService

val api = ApiBrasil.fromEnv
val sessao = api.auth.login(Json.obj("email" -> email, "password" -> senha)).orThrow

val autenticado =
  if (AuthService.requires2fa(sessao)) {
    val desafio = sessao("challenge")

    api.auth.send2fa(Json.obj("challenge" -> desafio, "method" -> "email")).orThrow
    val confirmada = api.auth.verify2fa(Json.obj("challenge" -> desafio, "code" -> "000000")).orThrow

    api.authenticate(confirmada)
  } else api.authenticate(sessao)
```

## 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)  | `api.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:

```scala
import br.com.apibrasil.sdk.core.RequestOptions

val device = api
  .withOptions(RequestOptions(secretKey = Some("SUA_SECRET_KEY")))
  .devices
  .store(Json.obj("device_name" -> "meu-bot", "type" -> "server"))
  .orThrow

val comDevice = api.withDeviceToken(device.string("device_token"))
```

O cliente é um valor imutável: `withDeviceToken`, `withBearerToken`, `withDevice` e `withOptions` devolvem sempre um **novo** cliente.

## Serviços disponíveis

| Acessor                                     | Descrição                                                                                  |
| ------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `api.whatsapp`                              | WhatsApp: `start`, `qrcode`, `sendText`, `sendFile`, `sendAudio`, fila (`.queue`)...        |
| `api.evolution`                             | Evolution API: `request` (controller + action), `call`, `queue`                             |
| `api.whatsmeow`                             | WhatsMeow: `sendText`, `instanceCreate`, `instanceQr`, `request`                            |
| `api.sms`                                   | SMS device-based (`send`) e por créditos (`sendWithCredits`)                                |
| `api.dados`                                 | Dados cadastrais device-based (`cpf`, `cnpj`, `listaSocios`...)                             |
| `api.vehicles`                              | Veículos por placa (`dados`, `fipe`, `consultaFipe`, `baseDados`)                           |
| `api.fipe`                                  | Tabela FIPE (`consultarMarcas`, `consultarModelos`...)                                      |
| `api.correios`                              | Correios (`rastreio`, `request`)                                                            |
| `api.cep`                                   | CEP + geolocalização (`cep`, `cidades`, `estados`, `calcularDistancia`)                     |
| `api.geolocation` / `api.geomatrix`         | Geocoding e matriz de distâncias                                                            |
| `api.recognize`                             | OCR / Google Vision (`base64`, `uri`)                                                       |
| `api.ddd` / `api.holidays` / `api.translate` / `api.weather` | DDD, feriados, tradução, clima                                             |
| `api.loterias`                              | Loterias (`latest`, `resultado`)                                                            |
| `api.databaseIp`                            | GeoIP (`ip`)                                                                                |
| `api.consulta`                              | Consultas por créditos: `cpf`, `cnpj`, `cnh`, `cep`, `veiculos`, `telefone`, `generic`      |
| `api.ura` / `api.chipVirtual`               | URA reversa e chip virtual                                                                  |
| `api.bulk`                                  | Execução em lote (`direct`, `queue`)                                                        |
| `api.auth`                                  | Login, 2FA, cadastro, recuperação de senha, perfil                                          |
| `api.devices`                               | CRUD de devices                                                                             |
| `api.catalog`                               | Catálogo de APIs, planos, documentações, servidores                                         |
| `api.account`                               | Saldo, faturas, notificações, tickets                                                       |
| `api.payments`                              | Recargas e pagamentos PIX/boleto/cartão (Santander, Inter, Mercado Pago, Sicoob)             |
| `api.ipWhitelist` / `api.bearerRateLimit`   | Segurança da conta                                                                          |
| `api.reports`                               | Relatórios e dashboard de consumo                                                           |

Toda função aceita o body como `Json` (ou nada) e termina com um `RequestOptions` opcional.

### WhatsApp

```scala
// iniciar sessão e obter QR Code
api.whatsapp.start(Json.obj("webhook_wh_message" -> "https://seu-webhook.com/mensagens"))

val qr = api.whatsapp.qrcode().orThrow
println(qr.response("qrcode").asString)
// => imagem do QR Code em base64

// envios
api.whatsapp.sendText(Json.obj("number" -> "5511999999999", "text" -> "Olá!"))

api.whatsapp.sendFile(
  Json.obj("number" -> "5511999999999", "path" -> "https://exemplo.com/boleto.pdf")
)

api.whatsapp.sendLocation(Json.obj("number" -> "5511999999999", "lat" -> -23.5, "lng" -> -46.6))

// qualquer action do catálogo
api.whatsapp.request("getAllChats")

// fila assíncrona
api.whatsapp.sendText.queue(Json.obj("number" -> "5511999999999", "text" -> "por fila"))
```

O envelope device-based tem acessores nomeados — e continua sendo o JSON completo:

```scala
val envelope = api.whatsapp.sendText(Json.obj("number" -> numero, "text" -> "Olá!")).orThrow

envelope.isError            // false
envelope.message            // Option[String] com a mensagem do gateway
envelope.response           // payload do provedor
envelope.apiLimit           // limite do plano

envelope("response")("id")  // acesso direto por chave
envelope.json               // o envelope completo
```

### Consultas por créditos

```scala
val cpf = api.consulta.cpf(Json.obj("cpf" -> "00000000000")).orThrow
(cpf.balance, cpf.data)

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

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

// qualquer serviço do catálogo, e os créditos disponíveis
api.consulta.generic("cnh", Json.obj("cpf" -> "00000000000"))
api.consulta.credits("cpf")
api.consulta.cpf.credits()
```

O builder também aceita `lite`, `withAgrupados`, `withExtra` e `withFields`; qualquer função de consulta recebe a `Consulta` diretamente no lugar do `Json`.

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

```scala
api.vehicles.dados(Json.obj("placa" -> "ABC1234"))
api.vehicles.fipe(Json.obj("placa" -> "ABC1234"))
api.fipe.consultarMarcas(Json.obj("codigoTabelaReferencia" -> 300))
```

### SMS

```scala
api.sms.send(Json.obj("number" -> "5511999999999", "message" -> "Olá!"))
api.sms.sendWithCredits(Json.obj("number" -> "5511999999999", "message" -> "Olá!"))
```

### Pagamentos e recargas

```scala
import br.com.apibrasil.sdk.platform.PaymentsService

api.payments.recharge(Json.obj("amount" -> 50, "type" -> "pix"))
api.payments.pixGenerate(PaymentsService.Santander, Json.obj("amount" -> 50))
api.payments.pixStatus(PaymentsService.Santander, "TX_ID")

// bytes crus do PDF
val pdf = api.payments.boletoPdf(PaymentsService.Inter, "ID").orThrow
java.nio.file.Files.write(java.nio.file.Paths.get("boleto.pdf"), pdf)
```

### Múltiplos devices

```scala
val bot1 = api.withDevice("device_token_1")
val bot2 = api.withDevice("device_token_2")

bot1.whatsapp.sendText(Json.obj("number" -> numero, "text" -> "do bot 1"))
bot2.whatsapp.sendText(Json.obj("number" -> numero, "text" -> "do bot 2"))
```

## Tratamento de erros

Toda chamada devolve `ApiResult[A]` — um `Either[ApiError, A]` — e a categoria da falha é a própria subclasse:

| Classe                     | Quando                                        |
| -------------------------- | --------------------------------------------- |
| `ValidationError`          | 400/422 — payload inválido                    |
| `AuthenticationError`      | 401 — token ausente/expirado                  |
| `InsufficientBalanceError` | 402 — sem saldo/créditos                      |
| `PermissionError`          | 403 — sem permissão (ex: exige PJ)            |
| `NotFoundError`            | 404/410 — sem dados / rota desativada         |
| `RateLimitError`           | 429 — limite atingido (`retryAfter`, em ms)   |
| `ServerError`              | 5xx — erro do gateway/provedor                |
| `NetworkError` / `TimeoutError` | falha antes da resposta                  |
| `GenericApiError`          | qualquer outra falha da API                   |

```scala
import br.com.apibrasil.sdk.core._

api.consulta.cpf(Json.obj("cpf" -> "00000000000")) match {
  case Right(consulta) =>
    println(consulta.data)

  case Left(_: InsufficientBalanceError) =>
    println("Recarregue seus créditos")

  case Left(erro: RateLimitError) =>
    println(s"Aguarde ${erro.retryAfter.getOrElse(0L)}ms")

  // detalhes completos da falha
  case Left(erro) =>
    println(s"${erro.getMessage} ${erro.status} ${erro.code} ${erro.kind}")
}
```

Como o resultado é um `Either`, ele encadeia em `for`-comprehension e nas combinações de sempre:

```scala
val resumo = for {
  saldo <- api.account.balance()
  plano <- api.account.plan()
} yield (saldo("balance"), plano("name"))
```

## `orThrow` e as outras formas do resultado

`orThrow` devolve o valor direto e levanta o `ApiError` — o equivalente às variantes `!` das demais SDKs da plataforma. Não precisa de import: a conversão está no escopo implícito do próprio tipo.

```scala
val envelope = api.whatsapp.sendText(Json.obj("number" -> numero, "text" -> "Olá!")).orThrow
println(envelope.response)

try api.account.balance().orThrow
catch { case erro: ApiError => println(erro.getMessage) }

// o mesmo resultado nas outras formas
api.account.balance().toTry      // Try[Json]
api.account.balance().toOption   // Option[Json]
api.account.balance().error      // Option[ApiError]
```

## Chamadas assíncronas

A SDK é síncrona e sem estado global, então qualquer `ExecutionContext` serve:

```scala
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

val envio = Future(api.whatsapp.sendText(Json.obj("number" -> numero, "text" -> "Olá!")))

// vários envios em paralelo
val todos = Future.traverse(numeros)(numero =>
  Future(api.whatsapp.sendText(Json.obj("number" -> numero, "text" -> "Olá!")))
)
```

O transporte padrão compartilha um pool de conexões entre todos os clientes, e a instância é segura para uso concorrente.

## 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.

```scala
val api = ApiBrasil(
  retry = Some(RetryConfig(retries = 3, minDelay = 500, maxDelay = 5000, retryOnStatuses = Set(429, 503))),
  hooks = Some(new Hooks {
    override def onRequest(info: RequestInfo): Unit =
      println(s"→ ${info.method} ${info.url} (#${info.attempt})")
    override def onResponse(info: ResponseInfo): Unit =
      println(s"← ${info.status} em ${info.duration}ms")
    override def onRetry(info: RetryInfo): Unit =
      println(s"retry em ${info.delay}ms: ${info.reason}")
  })
)

// ou desativando o retry
ApiBrasil(retry = Some(RetryConfig.none))
```

Para um gancho só, use os atalhos: `Hooks.onResponse(info => metrics.timing("apibrasil", info.duration))`. Falhas dentro de um hook nunca derrubam a requisição.

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

```scala
api.whatsapp.sendText(body, RequestOptions(timeout = Some(java.time.Duration.ofSeconds(10))))
```

## Opções por requisição

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

```scala
api
  .withOptions(
    RequestOptions(
      secretKey = Some("SUA_SECRET_KEY"),
      headers = Map("X-Correlation-Id" -> "abc-123"),
      timeout = Some(java.time.Duration.ofSeconds(5))
    )
  )
  .devices
  .store(Json.obj("device_name" -> "meu-bot"))

// ou só nesta chamada — o RequestOptions é sempre o último argumento
api.whatsapp.sendText(body, RequestOptions(deviceToken = Some("outro-device")))
```

Campos aceitos: `query`, `headers`, `bearerToken`, `deviceToken`, `secretKey`, `timeout` e `responseType` (`Json` ou `Binary`).

## Transporte plugável

O HTTP padrão é o `java.net.http.HttpClient` (`JdkHttpTransport`, sem dependências), mas o trait `Transport` permite trocar a camada inteira — proxy corporativo, instrumentação, mocks de teste:

```scala
import java.net.http.HttpClient
import br.com.apibrasil.sdk.core.transport.JdkHttpTransport

val transport = JdkHttpTransport(
  HttpClient
    .newBuilder()
    .proxy(java.net.ProxySelector.of(new java.net.InetSocketAddress("proxy.empresa", 3128)))
    .connectTimeout(java.time.Duration.ofSeconds(5))
    .build()
)

ApiBrasil(transport = Some(transport))
```

`Transport` é uma SAM, então em testes ele pode ser **uma função** — sem rede, sem mock library:

```scala
import br.com.apibrasil.sdk.core._

val api = ApiBrasil(
  bearerToken = Some("token-de-teste"),
  deviceToken = Some("device-de-teste"),
  transport = Some((request: TransportRequest) =>
    Right(TransportResponse.json(200, Json.obj("error" -> false, "response" -> Json.obj("id" -> "ABC"))))
  )
)

val envelope = api.whatsapp.sendText(Json.obj("number" -> "5511999999999", "text" -> "oi")).orThrow

assert(envelope.response("id").asString.contains("ABC"))
```

## JSON sem dependências

`Json` é uma ADT fechada (`Null`, `Bool`, `Num`, `Str`, `Arr`, `Obj`) com parser e serializador próprios — a SDK nunca conflita com a biblioteca JSON do seu projeto.

```scala
// montar
Json.obj(
  "number" -> "5511999999999",
  "text" -> "Olá!",
  "tags" -> Seq("a", "b"),
  "options" -> Json.obj("delay" -> 1200)
)

// ler — campo ausente devolve Json.Null em qualquer profundidade, nunca levanta
resposta("data")("nome").asString      // Option[String]
resposta("data")("idade").asInt        // Option[Int]
resposta("balance").asBigDecimal       // Option[BigDecimal]
resposta("itens").elements             // Vector[Json]
resposta.boolean("error")              // Boolean (false quando ausente)
resposta \ "data" \ "nome"             // Json

// converter
Json.parse(texto)        // Either[String, Json]
resposta.compact         // String em uma linha
resposta.pretty          // String indentada
```

Para mapear a resposta em `case class` do seu projeto, use a sua biblioteca preferida sobre `resposta.compact`.

## 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
sbt "codegen/runMain br.com.apibrasil.sdk.codegen.Codegen"
```

```scala
import br.com.apibrasil.sdk.generated.Catalog

Catalog.actionsFor("whatsapp")           // todas as actions do WhatsApp
Catalog.actionsFor("cep")                // Seq("bairros", "cep", "cidades", ...)
Catalog.hasAction("cep", "estados")      // true
Catalog.evolutionPaths                   // Seq("call/offer", "chat/deleteMessageForEveryone", ...)
Catalog.consultaServicos                 // serviços de /consulta/{servico}/credits
Catalog.consultaTipos                    // os `tipo` conhecidos das consultas
Catalog.consultaTipo("acerta-essencial") // Some(ConsultaTipo("cpf", Seq("cpf")))
```

## Endpoint sem função dedicada?

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

```scala
import br.com.apibrasil.sdk.core.HttpMethod

api.request(HttpMethod.POST, "/consulta/cpf/credits", Json.obj("cpf" -> "00000000000"))
api.request(HttpMethod.GET, "/reports/quick-stats")

// corpo decodificado sem normalizar em objeto JSON (listas, texto)
api.execute(HttpMethod.GET, "/plans")

// bytes crus (PDF de boleto, imagens)
api.download("/inter/boleto/ID/pdf")
```

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

## Configuração avançada

```scala
import java.time.Duration
import br.com.apibrasil.sdk.core._

val api = ApiBrasil(
  // ou APIBRASIL_BEARER_TOKEN
  bearerToken = Some("..."),
  // ou APIBRASIL_DEVICE_TOKEN
  deviceToken = Some("..."),
  // usada em api.devices.store (ou APIBRASIL_SECRET_KEY)
  secretKey = Some("..."),
  // padrão (ou APIBRASIL_BASE_URL)
  baseUrl = Some("https://gateway.apibrasil.io/api/v2"),
  timeout = Some(Duration.ofSeconds(30)),
  headers = Map("X-Correlation-Id" -> "abc-123"),
  transport = Some(JdkHttpTransport.shared),
  retry = Some(RetryConfig(retries = 3)),
  hooks = Some(Hooks.onResponse(info => println(info.status))),
  options = RequestOptions(timeout = Some(Duration.ofSeconds(15)))
)
```

O que você passa em `ApiBrasil(...)` tem prioridade sobre o ambiente. Credenciais vazias contam como ausentes: informar `Some("")` é a forma de desligar o que veio do ambiente. `Config` também pode ser montado à parte e passado inteiro — `ApiBrasil(config)`.

Nem `Client.toString` nem `Config.toString` expõem credenciais.

## Interface legada

`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 em `Right` em vez de `Left`.

```scala
val legacy = Legacy()

val dados = """{
  "action": "sendText",
  "credentials": {
    "DeviceToken": "SEU_DEVICE_TOKEN",
    "BearerToken": "SEU_BEARER_TOKEN"
  },
  "body": {"number": "5511999999999", "text": "Hello World for Scala"}
}"""

legacy.whatsapp(dados)
```

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

Ele 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 funções dedicadas, erros com categoria, retry e hooks.

## Exemplos executáveis

Os exemplos em [`examples/`](https://github.com/APIBrasil/apigratis-sdk-scala/blob/main/examples) rodam com [scala-cli](https://scala-cli.virtuslab.org):

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

scala-cli run examples/Basico.scala
scala-cli run examples/WhatsApp.scala -- 5511999999999
```

## Desenvolvimento

```bash
sbt test                # testes na versão padrão do Scala
sbt +test               # testes em Scala 2.13 e 3.3
sbt scalafmtAll         # formatação
sbt +package            # jars das duas versões
sbt doc                 # scaladoc

sbt "codegen/runMain br.com.apibrasil.sdk.codegen.Codegen"   # regenera o catálogo
```

A suíte não faz nenhuma chamada de rede: o `FakeTransport` responde a tudo.

## Licença

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

## A mesma API por HTTP

Endereço base: https://gateway.apibrasil.io/api/v2
O caminho e o método de cada endpoint estão na página daquela API nesta documentação. Não deduza rota a partir do nome do serviço.

### Autenticação, em cabeçalhos HTTP
- `Authorization: Bearer SEU_TOKEN` — em toda chamada.
- `DeviceToken: SEU_DEVICE_TOKEN` — só nas APIs cobradas por plano; as cobradas por crédito não pedem. O nome exato do cabeçalho é o que a página do endpoint declara.

```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}'
```

Com `homolog` verdadeiro no corpo, o gateway responde de uma base fixa e não consome crédito. O CPF 00000000000 é dessa base e não é de ninguém — use-o nos testes, nunca em produção.

## As outras linguagens

- [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`
- [Lua](https://doc.apibrasil.io/sdks/lua.md): `luarocks install apibrasil`
- [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`

## Ver também

- SDKs oficiais: [SDKs oficiais](https://doc.apibrasil.io/sdks.md)
- Índice da documentação: https://doc.apibrasil.io/llms.txt
- Versão HTML desta página: https://doc.apibrasil.io/sdks/scala
