Skip to main content

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}