apibrasil/lib.rs
1//! SDK oficial Rust da plataforma [APIBrasil](https://apibrasil.com.br) —
2//! WhatsApp, SMS, consultas de CPF/CNPJ, veículos, CEP, correios,
3//! pagamentos PIX/boleto e muito mais.
4//!
5//! ```no_run
6//! use apibrasil::{ApiBrasil, Config};
7//! use serde_json::json;
8//!
9//! #[tokio::main]
10//! async fn main() -> apibrasil::Result<()> {
11//! let api = ApiBrasil::new(
12//! Config::new()
13//! .bearer_token("SEU_BEARER_TOKEN") // JWT do login
14//! .device_token("SEU_DEVICE_TOKEN"), // device dos serviços device-based
15//! );
16//!
17//! // WhatsApp
18//! api.whatsapp()
19//! .send_text(json!({ "number": "5511999999999", "text": "Olá! 👋" }))
20//! .await?;
21//!
22//! // Consulta CNPJ (por créditos)
23//! let empresa = api.consulta().cnpj(json!({ "cnpj": "00000000000000" })).await?;
24//! println!("{:?}", empresa.data());
25//!
26//! Ok(())
27//! }
28//! ```
29//!
30//! Credenciais não informadas são lidas das variáveis de ambiente
31//! [`APIBRASIL_BEARER_TOKEN`](core::ENV_BEARER_TOKEN),
32//! [`APIBRASIL_DEVICE_TOKEN`](core::ENV_DEVICE_TOKEN),
33//! [`APIBRASIL_SECRET_KEY`](core::ENV_SECRET_KEY) e
34//! [`APIBRASIL_BASE_URL`](core::ENV_BASE_URL) — basta
35//! [`ApiBrasil::from_env`].
36//!
37//! # Como a plataforma funciona
38//!
39//! | Família | Autenticação | Exemplos |
40//! | --- | --- | --- |
41//! | **Device-based** | `Authorization: Bearer` + header `DeviceToken` | WhatsApp, SMS, veículos, CEP, correios, DDD, feriados, tradução, clima, OCR |
42//! | **Por créditos** | apenas `Authorization: Bearer` (debita saldo) | [`consulta`](ApiBrasil::consulta): CPF, CNPJ, veículos, Serasa, CNH, telefone |
43//!
44//! # Features
45//!
46//! - `rustls-tls` (padrão) — TLS via rustls, sem depender de OpenSSL.
47//! - `native-tls` — TLS pela biblioteca do sistema.
48//! - `blocking` — cliente síncrono em [`blocking`], sobre um runtime
49//! Tokio próprio.
50
51#![warn(missing_docs)]
52#![cfg_attr(docsrs, feature(doc_cfg))]
53
54#[macro_use]
55mod macros;
56
57pub mod core;
58pub mod generated;
59pub mod legacy;
60pub mod services;
61
62#[cfg(feature = "blocking")]
63#[cfg_attr(docsrs, doc(cfg(feature = "blocking")))]
64pub mod blocking;
65
66use std::sync::Arc;
67
68pub use self::core::{
69 Config, Consulta, CreditResponse, DeviceResponse, Error, ErrorKind, FnHooks, Hooks, HttpClient,
70 IntoBody, Json, Method, RequestHookInfo, RequestOptions, ReqwestTransport, ResponseData,
71 ResponseHookInfo, ResponseType, Result, RetryConfig, RetryHookInfo, Transport,
72 TransportRequest, TransportResponse, DEFAULT_BASE_URL, DEFAULT_TIMEOUT, USER_AGENT,
73};
74pub use self::services::data::{
75 BulkService, CepService, ChipVirtualService, ConsultaService, CorreiosService, DadosService,
76 DatabaseIpService, DddService, FipeService, GeolocationService, GeomatrixService,
77 HolidaysService, LoteriasService, RecognizeService, TranslateService, UraService,
78 VehiclesService, WeatherService,
79};
80pub use self::services::messaging::{
81 EvolutionService, SmsService, WhatsAppService, WhatsMeowService,
82};
83pub use self::services::platform::{
84 extract_token, requires_2fa, AccountService, AuthService, BearerRateLimitService,
85 CatalogService, DevicesService, IpWhitelistService, PaymentsService, ReportsService,
86};
87pub use self::services::{BaseService, CreditService, DeviceProxyService};
88
89/// Cliente da plataforma APIBrasil.
90///
91/// Todos os serviços compartilham o mesmo [`HttpClient`] — um
92/// [`set_bearer_token`](Self::set_bearer_token) vale para todos. Clonar o
93/// cliente é barato (um [`Arc`]) e mantém o estado compartilhado.
94#[derive(Clone, Debug)]
95pub struct ApiBrasil {
96 http: Arc<HttpClient>,
97 options: RequestOptions,
98}
99
100/// Alias de [`ApiBrasil`], para leitura equivalente às demais SDKs da
101/// plataforma.
102pub type Client = ApiBrasil;
103
104impl ApiBrasil {
105 /// Cria o cliente. Campos não informados na `config` vêm do
106 /// ambiente.
107 pub fn new(config: Config) -> Self {
108 Self::with_http(Arc::new(HttpClient::new(config)))
109 }
110
111 /// Cria o cliente apenas com as credenciais do ambiente.
112 pub fn from_env() -> Self {
113 Self::new(Config::default())
114 }
115
116 /// Cria o cliente sobre um [`HttpClient`] já configurado.
117 pub fn with_http(http: Arc<HttpClient>) -> Self {
118 Self {
119 http,
120 options: RequestOptions::default(),
121 }
122 }
123
124 /// Cliente HTTP interno (headers, base URL, retry, hooks, erros).
125 pub fn http(&self) -> &Arc<HttpClient> {
126 &self.http
127 }
128
129 /// Opções aplicadas a todas as chamadas deste cliente.
130 pub fn options(&self) -> &RequestOptions {
131 &self.options
132 }
133
134 /// Devolve um cliente que usa `options` em todas as chamadas —
135 /// mesma conexão e mesmas credenciais.
136 pub fn with_options(&self, options: RequestOptions) -> Self {
137 Self {
138 http: self.http.clone(),
139 options,
140 }
141 }
142
143 /// Configuração atual do cliente.
144 pub fn config(&self) -> Config {
145 self.http.config()
146 }
147
148 /// Define/atualiza o Bearer Token do cliente.
149 pub fn set_bearer_token(&self, token: impl Into<String>) -> &Self {
150 self.http.set_bearer_token(Some(token.into()));
151 self
152 }
153
154 /// Remove o Bearer Token do cliente.
155 pub fn clear_bearer_token(&self) -> &Self {
156 self.http.set_bearer_token(None);
157 self
158 }
159
160 /// Define/atualiza o DeviceToken do cliente.
161 pub fn set_device_token(&self, token: impl Into<String>) -> &Self {
162 self.http.set_device_token(Some(token.into()));
163 self
164 }
165
166 /// Remove o DeviceToken do cliente.
167 pub fn clear_device_token(&self) -> &Self {
168 self.http.set_device_token(None);
169 self
170 }
171
172 /// Devolve um novo cliente com as mesmas credenciais, mas apontando
173 /// para outro device — útil para gerenciar vários
174 /// números/instâncias.
175 ///
176 /// ```no_run
177 /// # use apibrasil::ApiBrasil;
178 /// # use serde_json::json;
179 /// # async fn exemplo(api: ApiBrasil) -> apibrasil::Result<()> {
180 /// let bot1 = api.with_device("device_token_1");
181 /// let bot2 = api.with_device("device_token_2");
182 ///
183 /// bot1.whatsapp().send_text(json!({ "number": "5511999999999", "text": "do bot 1" })).await?;
184 /// bot2.whatsapp().send_text(json!({ "number": "5511999999999", "text": "do bot 2" })).await?;
185 /// # Ok(())
186 /// # }
187 /// ```
188 pub fn with_device(&self, device_token: impl Into<String>) -> Self {
189 let mut config = self.http.config();
190 config.device_token = Some(device_token.into());
191 Self::new(config)
192 }
193
194 /// Porta de saída genérica: chama qualquer endpoint do gateway com os
195 /// headers de autenticação já configurados. Use para rotas que ainda
196 /// não têm método dedicado na SDK.
197 ///
198 /// ```no_run
199 /// # use apibrasil::{ApiBrasil, Method};
200 /// # use serde_json::json;
201 /// # async fn exemplo(api: ApiBrasil) -> apibrasil::Result<()> {
202 /// api.request(Method::Post, "/consulta/cpf/credits", json!({ "cpf": "00000000000" })).await?;
203 /// api.request(Method::Get, "/reports/quick-stats", None).await?;
204 /// # Ok(())
205 /// # }
206 /// ```
207 pub async fn request(&self, method: Method, path: &str, body: impl IntoBody) -> Result<Json> {
208 self.http
209 .request_json(method, path, body.into_body(), &self.options)
210 .await
211 }
212
213 /// Como [`request`](Self::request), mas devolve o corpo decodificado
214 /// sem normalizar em objeto JSON (útil quando a rota responde uma
215 /// lista, texto ou bytes).
216 pub async fn execute(
217 &self,
218 method: Method,
219 path: &str,
220 body: impl IntoBody,
221 ) -> Result<ResponseData> {
222 self.http
223 .execute(method, path, body.into_body(), &self.options)
224 .await
225 }
226
227 /// Baixa os bytes crus de uma rota (PDF de boleto, imagens...).
228 pub async fn download(&self, path: &str) -> Result<Vec<u8>> {
229 self.http
230 .bytes(Method::Get, path, None, &self.options)
231 .await
232 }
233}
234
235/// Declara os acessores de serviço do cliente.
236macro_rules! client_services {
237 (
238 $(
239 $(#[$meta:meta])*
240 $method:ident -> $service:ident
241 ),* $(,)?
242 ) => {
243 impl ApiBrasil {
244 $(
245 $(#[$meta])*
246 pub fn $method(&self) -> $service {
247 $service::new(self.http.clone()).with_options(self.options.clone())
248 }
249 )*
250 }
251 };
252}
253
254client_services! {
255 /// Login, 2FA, cadastro, recuperação de senha e perfil.
256 auth -> AuthService,
257 /// CRUD de devices (criar, listar, atualizar, remover).
258 devices -> DevicesService,
259
260 /// WhatsApp device-based (`/whatsapp/{action}`).
261 whatsapp -> WhatsAppService,
262 /// Evolution API (`/evolution/{controller}/{action}`).
263 evolution -> EvolutionService,
264 /// WhatsMeow (`/whatsmeow/{action}`).
265 whatsmeow -> WhatsMeowService,
266 /// SMS (`/sms/{action}` e `/sms/send/credits`).
267 sms -> SmsService,
268
269 /// Dados cadastrais device-based (`/dados/cpf`, `/dados/cnpj`...).
270 dados -> DadosService,
271 /// Veículos por placa (`/vehicles/dados`, `/vehicles/fipe`).
272 vehicles -> VehiclesService,
273 /// Tabela FIPE (`/fipe/{action}`).
274 fipe -> FipeService,
275 /// Correios (`/correios/{action}`).
276 correios -> CorreiosService,
277 /// CEP + geolocalização (`/cep/{action}`).
278 cep -> CepService,
279 /// Geolocalização (`/geolocation/{action}`).
280 geolocation -> GeolocationService,
281 /// Matriz de distâncias (`/geomatrix/{action}`).
282 geomatrix -> GeomatrixService,
283 /// OCR / Google Vision (`/recognize/{action}`).
284 recognize -> RecognizeService,
285 /// DDD (`/ddd/{action}`).
286 ddd -> DddService,
287 /// Feriados (`/holidays/{action}`).
288 holidays -> HolidaysService,
289 /// Tradução (`/translate/{action}`).
290 translate -> TranslateService,
291 /// Clima (`/weather/{action}`).
292 weather -> WeatherService,
293 /// Loterias (`/loterias/{sorteio}/*`).
294 loterias -> LoteriasService,
295 /// GeoIP (`/database/ip`).
296 database_ip -> DatabaseIpService,
297
298 /// Consultas por crédito (`/consulta/{servico}/credits`).
299 consulta -> ConsultaService,
300 /// URA reversa / ligações (`/ura/call/*`).
301 ura -> UraService,
302 /// Chip virtual (`/chip/virtual/*`).
303 chip_virtual -> ChipVirtualService,
304 /// Execução em lote (`/bulk/*`).
305 bulk -> BulkService,
306
307 /// Catálogo de APIs, planos, documentações e servidores.
308 catalog -> CatalogService,
309 /// Saldo, faturas, notificações e tickets.
310 account -> AccountService,
311 /// Recargas e pagamentos (PIX, boleto, cartão).
312 payments -> PaymentsService,
313 /// Whitelist de IPs da conta.
314 ip_whitelist -> IpWhitelistService,
315 /// Rate limit por Bearer Token.
316 bearer_rate_limit -> BearerRateLimitService,
317 /// Relatórios e dashboard de consumo.
318 reports -> ReportsService,
319}
320
321/// Autentica por email/senha e devolve um cliente já autenticado, junto
322/// da sessão retornada pela plataforma.
323///
324/// ```no_run
325/// # use serde_json::json;
326/// # async fn exemplo() -> apibrasil::Result<()> {
327/// let (api, sessao) = apibrasil::login(
328/// json!({ "email": "voce@empresa.com.br", "password": "******" }),
329/// Default::default(),
330/// )
331/// .await?;
332/// # let _ = (api, sessao);
333/// # Ok(())
334/// # }
335/// ```
336///
337/// Devolve erro quando a conta exige 2FA — nesse caso crie o cliente com
338/// [`ApiBrasil::new`] e use [`AuthService::login`] +
339/// [`AuthService::send_2fa`] + [`AuthService::verify_2fa`].
340pub async fn login(credentials: impl IntoBody, config: Config) -> Result<(ApiBrasil, Json)> {
341 let api = ApiBrasil::new(config);
342 let session = api.auth().login(credentials).await?;
343
344 if requires_2fa(&session) {
345 return Err(Error::authentication(
346 "Esta conta exige autenticação em dois fatores. Use auth().login() + auth().verify_2fa().",
347 )
348 .with_response(session));
349 }
350
351 Ok((api, session))
352}