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

# Scala SDK

- **Status:** public code, no package yet
- **Install:** This SDK has not been published to any registry yet: there is no install command. The source is in the repository below.
- **Repository:** https://github.com/APIBrasil/apigratis-sdk-scala

## Do not make up the signature

DO NOT INVENT THE Scala 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:** Scala
- **Licence:** MIT License
- **Last push:** July 28, 2026
- **git clone:** `https://github.com/APIBrasil/apigratis-sdk-scala.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 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).

## 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`
- [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`

## 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/scala
