pypix-api 0.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Seu Nome
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: pypix-api
3
+ Version: 0.0.3
4
+ Summary: Biblioteca em Python para comunicação com APIs bancárias focada na integração com o PIX
5
+ Author-email: Fábio Thomaz <fabio@ladder.dev.br>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Seu Nome
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/laddertech/pypix-api
29
+ Project-URL: Repository, https://github.com/laddertech/pypix-api
30
+ Keywords: pix,api,banco,pagamento,brasil
31
+ Classifier: Programming Language :: Python :: 3
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Operating System :: OS Independent
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
36
+ Requires-Python: >=3.10
37
+ Description-Content-Type: text/markdown
38
+ License-File: LICENSE
39
+ Requires-Dist: requests>=2.25.1
40
+ Requires-Dist: python-dotenv>=0.15.0
41
+ Requires-Dist: requests-pkcs12>=1.25
42
+ Provides-Extra: dev
43
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
44
+ Requires-Dist: pytest-mock>=3.6.1; extra == "dev"
45
+ Requires-Dist: build>=1.2.2.post1; extra == "dev"
46
+ Requires-Dist: twine>=6.1.0; extra == "dev"
47
+ Requires-Dist: ruff>=0.4.2; extra == "dev"
48
+ Dynamic: license-file
49
+
50
+ # pypix-api
51
+
52
+ Biblioteca em Python para comunicação com APIs bancárias, focada na integração com o PIX.
53
+
54
+ ## Sumário
55
+
56
+ - [pypix-api](#pypix-api)
57
+ - [Sumário](#sumário)
58
+ - [Visão Geral](#visão-geral)
59
+ - [Instalação](#instalação)
60
+ - [Exemplo de Uso](#exemplo-de-uso)
61
+ - [Estrutura do Projeto](#estrutura-do-projeto)
62
+ - [Configuração](#configuração)
63
+ - [Testes](#testes)
64
+ - [Contribuição](#contribuição)
65
+ - [Licença](#licença)
66
+
67
+ ## Visão Geral
68
+
69
+ O `pypix-api` facilita a integração de sistemas Python com APIs bancárias brasileiras, com ênfase no ecossistema do PIX. A biblioteca abstrai autenticação, comunicação segura (MTLS/OAuth2), e operações comuns de bancos como Banco do Brasil e Sicoob.
70
+
71
+ ## Instalação
72
+
73
+ Recomenda-se o uso de ambiente virtual.
74
+
75
+ ```bash
76
+ pip install .
77
+ ```
78
+
79
+ Ou, para desenvolvimento:
80
+
81
+ ```bash
82
+ git clone https://github.com/seu-usuario/pypix-api.git
83
+ cd pypix-api
84
+ pip install -e .
85
+ ```
86
+
87
+ ## Exemplo de Uso
88
+
89
+ ```python
90
+ from pypix_api.banks.bb import BancoDoBrasil
91
+
92
+ # Instanciação do banco (OAuth2 é inicializado internamente)
93
+ bb = BancoDoBrasil(
94
+ client_id="SEU_CLIENT_ID",
95
+ client_secret="SEU_CLIENT_SECRET",
96
+ cert_path="caminho/do/certificado.pem",
97
+ key_path="caminho/da/chave.key"
98
+ )
99
+
100
+ # Exemplo: Cobrança com Vencimento
101
+ payload = {
102
+ "calendario": {
103
+ "dataDeVencimento": "2025-12-31",
104
+ "validadeAposVencimento": 30
105
+ },
106
+ "loc": {
107
+ "id": 789
108
+ },
109
+ "devedor": {
110
+ "logradouro": "Alameda Souza, Numero 80, Bairro Braz",
111
+ "cidade": "Recife",
112
+ "uf": "PE",
113
+ "cep": "70011750",
114
+ "cpf": "12345678909",
115
+ "nome": "Francisco da Silva"
116
+ },
117
+ "valor": {
118
+ "original": "123.45",
119
+ "multa": {
120
+ "modalidade": "2",
121
+ "valorPerc": "15.00"
122
+ },
123
+ "juros": {
124
+ "modalidade": "2",
125
+ "valorPerc": "2.00"
126
+ },
127
+ "desconto": {
128
+ "modalidade": "1",
129
+ "descontoDataFixa": [
130
+ {
131
+ "data": "2025-11-30",
132
+ "valorPerc": "30.00"
133
+ }
134
+ ]
135
+ }
136
+ },
137
+ "chave": "5f84a4c5-c5cb-4599-9f13-7eb4d419dacc",
138
+ "solicitacaoPagador": "Cobrança dos serviços prestados."
139
+ }
140
+ cobv = bb.criar_cobv(txid="uuid-unico", body=payload)
141
+ print(cobv)
142
+ ```
143
+
144
+ ## Estrutura do Projeto
145
+
146
+ ```
147
+ pypix_api/
148
+ ├── auth/ # Autenticação (MTLS, OAuth2)
149
+ ├── banks/ # Integrações com bancos (BB, Sicoob, métodos PIX)
150
+ ├── models/ # Modelos de dados do PIX
151
+ ├── utils/ # Utilitários (HTTP client, helpers)
152
+ tests/ # Testes automatizados
153
+ openapi.yaml # Especificação OpenAPI (se aplicável)
154
+ pyproject.toml # Configuração do projeto Python
155
+ Makefile # Comandos úteis para desenvolvimento
156
+ .env.exemplo # Exemplo de variáveis de ambiente
157
+ ```
158
+
159
+ ## Configuração
160
+
161
+ Crie um arquivo `.env` baseado em `.env.exemplo` com as credenciais e configurações necessárias para autenticação e acesso às APIs bancárias.
162
+
163
+ ## Testes
164
+
165
+ Para rodar os testes automatizados:
166
+
167
+ ```bash
168
+ make test
169
+ ```
170
+ ou diretamente com pytest:
171
+ ```bash
172
+ pytest
173
+ ```
174
+
175
+ ## Contribuição
176
+
177
+ Contribuições são bem-vindas! Siga os passos:
178
+
179
+ 1. Fork este repositório
180
+ 2. Crie uma branch (`git checkout -b feature/nova-funcionalidade`)
181
+ 3. Commit suas alterações (`git commit -am 'Adiciona nova funcionalidade'`)
182
+ 4. Push para a branch (`git push origin feature/nova-funcionalidade`)
183
+ 5. Abra um Pull Request
184
+
185
+ ## Licença
186
+
187
+ Este projeto está licenciado sob os termos da licença MIT.
@@ -0,0 +1,138 @@
1
+ # pypix-api
2
+
3
+ Biblioteca em Python para comunicação com APIs bancárias, focada na integração com o PIX.
4
+
5
+ ## Sumário
6
+
7
+ - [pypix-api](#pypix-api)
8
+ - [Sumário](#sumário)
9
+ - [Visão Geral](#visão-geral)
10
+ - [Instalação](#instalação)
11
+ - [Exemplo de Uso](#exemplo-de-uso)
12
+ - [Estrutura do Projeto](#estrutura-do-projeto)
13
+ - [Configuração](#configuração)
14
+ - [Testes](#testes)
15
+ - [Contribuição](#contribuição)
16
+ - [Licença](#licença)
17
+
18
+ ## Visão Geral
19
+
20
+ O `pypix-api` facilita a integração de sistemas Python com APIs bancárias brasileiras, com ênfase no ecossistema do PIX. A biblioteca abstrai autenticação, comunicação segura (MTLS/OAuth2), e operações comuns de bancos como Banco do Brasil e Sicoob.
21
+
22
+ ## Instalação
23
+
24
+ Recomenda-se o uso de ambiente virtual.
25
+
26
+ ```bash
27
+ pip install .
28
+ ```
29
+
30
+ Ou, para desenvolvimento:
31
+
32
+ ```bash
33
+ git clone https://github.com/seu-usuario/pypix-api.git
34
+ cd pypix-api
35
+ pip install -e .
36
+ ```
37
+
38
+ ## Exemplo de Uso
39
+
40
+ ```python
41
+ from pypix_api.banks.bb import BancoDoBrasil
42
+
43
+ # Instanciação do banco (OAuth2 é inicializado internamente)
44
+ bb = BancoDoBrasil(
45
+ client_id="SEU_CLIENT_ID",
46
+ client_secret="SEU_CLIENT_SECRET",
47
+ cert_path="caminho/do/certificado.pem",
48
+ key_path="caminho/da/chave.key"
49
+ )
50
+
51
+ # Exemplo: Cobrança com Vencimento
52
+ payload = {
53
+ "calendario": {
54
+ "dataDeVencimento": "2025-12-31",
55
+ "validadeAposVencimento": 30
56
+ },
57
+ "loc": {
58
+ "id": 789
59
+ },
60
+ "devedor": {
61
+ "logradouro": "Alameda Souza, Numero 80, Bairro Braz",
62
+ "cidade": "Recife",
63
+ "uf": "PE",
64
+ "cep": "70011750",
65
+ "cpf": "12345678909",
66
+ "nome": "Francisco da Silva"
67
+ },
68
+ "valor": {
69
+ "original": "123.45",
70
+ "multa": {
71
+ "modalidade": "2",
72
+ "valorPerc": "15.00"
73
+ },
74
+ "juros": {
75
+ "modalidade": "2",
76
+ "valorPerc": "2.00"
77
+ },
78
+ "desconto": {
79
+ "modalidade": "1",
80
+ "descontoDataFixa": [
81
+ {
82
+ "data": "2025-11-30",
83
+ "valorPerc": "30.00"
84
+ }
85
+ ]
86
+ }
87
+ },
88
+ "chave": "5f84a4c5-c5cb-4599-9f13-7eb4d419dacc",
89
+ "solicitacaoPagador": "Cobrança dos serviços prestados."
90
+ }
91
+ cobv = bb.criar_cobv(txid="uuid-unico", body=payload)
92
+ print(cobv)
93
+ ```
94
+
95
+ ## Estrutura do Projeto
96
+
97
+ ```
98
+ pypix_api/
99
+ ├── auth/ # Autenticação (MTLS, OAuth2)
100
+ ├── banks/ # Integrações com bancos (BB, Sicoob, métodos PIX)
101
+ ├── models/ # Modelos de dados do PIX
102
+ ├── utils/ # Utilitários (HTTP client, helpers)
103
+ tests/ # Testes automatizados
104
+ openapi.yaml # Especificação OpenAPI (se aplicável)
105
+ pyproject.toml # Configuração do projeto Python
106
+ Makefile # Comandos úteis para desenvolvimento
107
+ .env.exemplo # Exemplo de variáveis de ambiente
108
+ ```
109
+
110
+ ## Configuração
111
+
112
+ Crie um arquivo `.env` baseado em `.env.exemplo` com as credenciais e configurações necessárias para autenticação e acesso às APIs bancárias.
113
+
114
+ ## Testes
115
+
116
+ Para rodar os testes automatizados:
117
+
118
+ ```bash
119
+ make test
120
+ ```
121
+ ou diretamente com pytest:
122
+ ```bash
123
+ pytest
124
+ ```
125
+
126
+ ## Contribuição
127
+
128
+ Contribuições são bem-vindas! Siga os passos:
129
+
130
+ 1. Fork este repositório
131
+ 2. Crie uma branch (`git checkout -b feature/nova-funcionalidade`)
132
+ 3. Commit suas alterações (`git commit -am 'Adiciona nova funcionalidade'`)
133
+ 4. Push para a branch (`git push origin feature/nova-funcionalidade`)
134
+ 5. Abra um Pull Request
135
+
136
+ ## Licença
137
+
138
+ Este projeto está licenciado sob os termos da licença MIT.
File without changes
@@ -0,0 +1,34 @@
1
+ from typing import BinaryIO
2
+
3
+ import requests
4
+ import requests_pkcs12
5
+
6
+
7
+ def get_session_with_mtls(
8
+ cert: str | None = None,
9
+ pvk: str | None = None,
10
+ cert_pfx: str | bytes | BinaryIO | None = None,
11
+ pwd_pfx: str | None = None,
12
+ sandbox_mode: bool = False,
13
+ ) -> requests.Session:
14
+ session = requests.Session()
15
+
16
+ if not sandbox_mode:
17
+ if cert_pfx and pwd_pfx:
18
+ # Configura autenticação com PFX
19
+ pkcs12_adapter = requests_pkcs12.Pkcs12Adapter(
20
+ pkcs12_data=cert_pfx if isinstance(cert_pfx, bytes) else None,
21
+ pkcs12_filename=cert_pfx if isinstance(cert_pfx, str) else None,
22
+ pkcs12_password=pwd_pfx,
23
+ )
24
+ session.mount('https://', pkcs12_adapter)
25
+ elif cert and pvk:
26
+ # Configura autenticação com PEM (manter compatibilidade)
27
+ session.cert = (cert, pvk)
28
+ else:
29
+ raise ValueError(
30
+ 'É necessário fornecer certificado e chave privada (PEM) '
31
+ 'ou certificado PFX e senha'
32
+ )
33
+
34
+ return session
@@ -0,0 +1,99 @@
1
+ import os
2
+ import time
3
+ import requests
4
+ from typing import BinaryIO
5
+ from dotenv import load_dotenv
6
+
7
+ from pypix_api.auth.mtls import get_session_with_mtls
8
+
9
+
10
+ class OAuth2Client:
11
+ """Cliente OAuth2 para autenticação com a API"""
12
+
13
+ def __init__(
14
+ self,
15
+ token_url: str,
16
+ client_id: str | None = None,
17
+ cert: str | None = None,
18
+ pvk: str | None = None,
19
+ cert_pfx: str | bytes | BinaryIO | None = None,
20
+ pwd_pfx: str | None = None,
21
+ sandbox_mode: bool = False,
22
+ ) -> None:
23
+ """Inicializa o cliente OAuth2
24
+
25
+ Args:
26
+ client_id: Client ID para autenticação OAuth2
27
+ cert: Path para o certificado PEM (opcional)
28
+ pvk: Path para a chave privada PEM (opcional)
29
+ cert_pfx: Path ou dados do certificado PFX (opcional)
30
+ pwd_pfx: Senha do certificado PFX (opcional)
31
+ sandbox_mode: Se True, não requer certificado (default: False)
32
+ """
33
+ load_dotenv()
34
+
35
+ self.client_id = client_id or os.getenv('CLIENT_ID')
36
+ self.cert = cert or os.getenv('CERT')
37
+ self.pvk = pvk or os.getenv('PVK')
38
+ self.cert_pfx = cert_pfx or os.getenv('CERT_PFX')
39
+ self.pwd_pfx = pwd_pfx or os.getenv('PWD_PFX')
40
+
41
+ self.token_url = token_url # URL de autenticação OAuth2
42
+ self.token_cache = {} # Cache de tokens por escopo
43
+ self.session = requests.Session()
44
+
45
+ self.sandbox_mode = sandbox_mode
46
+
47
+ if not self.sandbox_mode:
48
+ self.session = get_session_with_mtls(
49
+ cert=self.cert,
50
+ pvk=self.pvk,
51
+ cert_pfx=self.cert_pfx,
52
+ pwd_pfx=self.pwd_pfx,
53
+ sandbox_mode=self.sandbox_mode,
54
+ )
55
+
56
+ def get_token(self, scope: str | None = None) -> str:
57
+ """Obtém ou renova o token de acesso para o escopo especificado
58
+
59
+ Args:
60
+ scope: Escopo(s) necessário(s) para a API. Exemplos:
61
+ - Cobrança por Boleto: "boletos_inclusao boletos_consulta boletos_alteracao webhooks_alteracao webhooks_consulta webhooks_inclusao"
62
+ - Conta Corrente: "cco_consulta cco_transferencias openid"
63
+ - Recebimento no PIX: "cob.write cob.read cobv.write cobv.read lotecobv.write lotecobv.read pix.write pix.read webhook.read webhook.write payloadlocation.write payloadlocation.read"
64
+
65
+ Returns:
66
+ str: Token de acesso válido para o escopo solicitado
67
+ """
68
+ # Usa escopo padrão se não especificado (para compatibilidade)
69
+ if scope is None:
70
+ scope = 'cco_extrato cco_consulta'
71
+
72
+ # Verifica se já existe token válido para este escopo
73
+ if scope in self.token_cache and not self._is_token_expired(scope):
74
+ return self.token_cache[scope]['access_token']
75
+
76
+ token_data = {
77
+ 'grant_type': 'client_credentials',
78
+ 'client_id': self.client_id,
79
+ 'scope': scope,
80
+ }
81
+
82
+ response = self.session.post(self.token_url, data=token_data)
83
+ response.raise_for_status()
84
+
85
+ token_info = response.json()
86
+ token_info['expires_at'] = time.time() + token_info['expires_in']
87
+
88
+ # Armazena o token no cache por escopo
89
+ self.token_cache[scope] = token_info
90
+
91
+ return token_info['access_token']
92
+
93
+ def _is_token_expired(self, scope: str) -> bool:
94
+ """Verifica se o token para o escopo especificado expirou"""
95
+ if scope not in self.token_cache or 'expires_at' not in self.token_cache[scope]:
96
+ return True
97
+ return (
98
+ time.time() >= self.token_cache[scope]['expires_at'] - 60
99
+ ) # 60s de margem
@@ -0,0 +1,50 @@
1
+ from abc import ABC
2
+ from typing import BinaryIO
3
+ from pypix_api.auth.oauth2 import OAuth2Client
4
+ from pypix_api.banks.cobv_methods import CobVMethods
5
+
6
+
7
+ class BankPixAPIBase(CobVMethods, ABC):
8
+ """Classe base abstrata para clientes Pix de bancos."""
9
+
10
+ BASE_URL = None
11
+ TOKEN_URL = None
12
+ SCOPES = None
13
+
14
+ def __init__(
15
+ self,
16
+ client_id: str | None = None,
17
+ cert: str | None = None,
18
+ pvk: str | None = None,
19
+ cert_pfx: str | bytes | BinaryIO | None = None,
20
+ pwd_pfx: str | None = None,
21
+ sandbox_mode: bool = False,
22
+ ) -> None:
23
+ if not self.BASE_URL or not self.TOKEN_URL or not self.SCOPES:
24
+ raise ValueError(
25
+ 'BASE_URL, TOKEN_URL e SCOPES devem ser definidos na subclasse.'
26
+ )
27
+ self.sandbox_mode = sandbox_mode
28
+ self.client_id = client_id
29
+
30
+ self.oauth = OAuth2Client(
31
+ token_url=self.TOKEN_URL,
32
+ client_id=client_id,
33
+ cert=cert,
34
+ pvk=pvk,
35
+ cert_pfx=cert_pfx,
36
+ pwd_pfx=pwd_pfx,
37
+ sandbox_mode=sandbox_mode,
38
+ )
39
+ self.session = self.oauth.session
40
+
41
+ def _create_headers(self) -> dict[str, str]:
42
+ """
43
+ Cria os headers necessários para as requisições.
44
+ """
45
+ token = self.oauth.get_token()
46
+ return {
47
+ 'Authorization': f'Bearer {token}',
48
+ 'Content-Type': 'application/json',
49
+ 'client_id': self.client_id or '',
50
+ }
@@ -0,0 +1,18 @@
1
+ from pypix_api.banks.base import BankPixAPIBase
2
+
3
+
4
+ class BBPixAPI(BankPixAPIBase):
5
+ """Banco do Brasil API client for Pix operations."""
6
+
7
+ BASE_URL = "https://api.bb.com.br/pix/v1"
8
+ SANDBOX_BASE_URL = "https://api.sandbox.bb.com.br/pix/v1"
9
+ TOKEN_URL = "https://oauth.bb.com.br/oauth/token"
10
+ SCOPES = "pix.read pix.write"
11
+
12
+ def get_base_url(self) -> str:
13
+ """
14
+ Retorna a URL base da API, diferenciando entre produção e sandbox.
15
+ """
16
+ if self.sandbox_mode:
17
+ return self.SANDBOX_BASE_URL
18
+ return self.BASE_URL
@@ -0,0 +1,101 @@
1
+ """
2
+ Módulo cobv_methods.py
3
+
4
+ Este módulo define a classe CobVMethods, que implementa métodos para
5
+ integração com cobranças Pix com vencimento (CobV) via API bancária.
6
+ Inclui operações para criar, revisar, consultar e listar cobranças com vencimento,
7
+ utilizando autenticação OAuth2 e requisições HTTP.
8
+
9
+ Principais funcionalidades:
10
+ - Criação de cobrança com vencimento (CobV)
11
+ - Revisão de cobrança com vencimento
12
+ - Consulta de cobrança por txid
13
+ - Listagem de cobranças por período e filtros
14
+
15
+ Dependências:
16
+ - OAuth2 para autenticação (self.oauth)
17
+ - Cliente HTTP de sessão (self.session)
18
+ - Python 3.10+ (tipos nativos)
19
+
20
+ Autor: [Fabio Thomaz(fabio@ladder.dev.br)]
21
+ """
22
+
23
+ from typing import Any
24
+
25
+
26
+ class CobVMethods: # pylint: disable=E1101
27
+ """
28
+ Métodos para lidar com cobrança Pix com vencimento (CobV).
29
+ """
30
+
31
+ def criar_cobv(self, txid: str, body: dict[str, Any]) -> dict[str, Any]:
32
+ """
33
+ Cria uma cobrança com vencimento (CobV).
34
+ """
35
+ headers = self._create_headers()
36
+ url = f'{self.get_base_url()}/cobv/{txid}'
37
+ resp = self.session.put(url, headers=headers, json=body)
38
+ resp.raise_for_status()
39
+ return resp.json()
40
+
41
+ def revisar_cobv(self, txid: str, body: dict[str, Any]) -> dict[str, Any]:
42
+ """
43
+ Revisa uma cobrança com vencimento (CobV).
44
+ """
45
+ headers = self._create_headers()
46
+ url = f'{self.get_base_url()}/cobv/{txid}'
47
+ resp = self.session.patch(url, headers=headers, json=body)
48
+ resp.raise_for_status()
49
+ return resp.json()
50
+
51
+ def consultar_cobv(
52
+ self, txid: str, revisao: int | None
53
+ ) -> dict[str, Any]:
54
+ """
55
+ Consulta uma cobrança com vencimento (CobV) por txid.
56
+ """
57
+ headers = self._create_headers()
58
+ params = {}
59
+ if revisao is not None:
60
+ params['revisao'] = revisao
61
+ url = f'{self.get_base_url()}/cobv/{txid}'
62
+ resp = self.session.get(url, headers=headers, params=params)
63
+ resp.raise_for_status()
64
+ return resp.json()
65
+
66
+ def listar_cobv(
67
+ self,
68
+ inicio: str,
69
+ fim: str,
70
+ cpf: str | None = None,
71
+ cnpj: str | None = None,
72
+ location_presente: bool | None = None,
73
+ status: str | None = None,
74
+ lote_cob_v_id: int | None = None,
75
+ pagina_atual: int | None = None,
76
+ itens_por_pagina: int | None = None,
77
+ ) -> dict[str, Any]:
78
+ """
79
+ Consulta lista de cobranças com vencimento (CobV).
80
+ """
81
+ headers = self._create_headers()
82
+ params = {'inicio': inicio, 'fim': fim}
83
+ if cpf:
84
+ params['cpf'] = cpf
85
+ if cnpj:
86
+ params['cnpj'] = cnpj
87
+ if location_presente is not None:
88
+ params['locationPresente'] = str(location_presente).lower()
89
+ if status:
90
+ params['status'] = status
91
+ if lote_cob_v_id is not None:
92
+ params['loteCobVId'] = lote_cob_v_id
93
+ if pagina_atual is not None:
94
+ params['paginaAtual'] = pagina_atual
95
+ if itens_por_pagina is not None:
96
+ params['itensPorPagina'] = itens_por_pagina
97
+
98
+ url = f'{self.get_base_url()}/cobv'
99
+ resp = self.session.get(url, headers=headers, params=params)
100
+ resp.raise_for_status()
101
+ return resp.json()
@@ -0,0 +1,20 @@
1
+ from pypix_api.banks.base import BankPixAPIBase
2
+
3
+
4
+ class SicoobPixAPI(BankPixAPIBase):
5
+ """Sicoob API client for Pix operations."""
6
+
7
+ BASE_URL = "https://api.sicoob.com.br/pix/api/v2"
8
+ SANDBOX_BASE_URL = "https://sandbox.sicoob.com.br/sicoob/sandbox/pix/api/v2"
9
+ TOKEN_URL = (
10
+ "https://auth.sicoob.com.br/auth/realms/sicoob/protocol/openid-connect/token"
11
+ )
12
+ SCOPES = "cob.read cob.write pix.read pix.write"
13
+
14
+ def get_base_url(self) -> str:
15
+ """
16
+ Retorna a URL base da API, diferenciando entre produção e sandbox.
17
+ """
18
+ if self.sandbox_mode:
19
+ return self.SANDBOX_BASE_URL
20
+ return self.BASE_URL
@@ -0,0 +1,9 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class PixCobranca:
6
+ txid: str
7
+ valor: float
8
+ status: str
9
+ chave: str
@@ -0,0 +1,5 @@
1
+ import requests
2
+
3
+
4
+ def get(url, headers=None, cert=None):
5
+ return requests.get(url, headers=headers, cert=cert)
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: pypix-api
3
+ Version: 0.0.3
4
+ Summary: Biblioteca em Python para comunicação com APIs bancárias focada na integração com o PIX
5
+ Author-email: Fábio Thomaz <fabio@ladder.dev.br>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Seu Nome
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/laddertech/pypix-api
29
+ Project-URL: Repository, https://github.com/laddertech/pypix-api
30
+ Keywords: pix,api,banco,pagamento,brasil
31
+ Classifier: Programming Language :: Python :: 3
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Operating System :: OS Independent
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
36
+ Requires-Python: >=3.10
37
+ Description-Content-Type: text/markdown
38
+ License-File: LICENSE
39
+ Requires-Dist: requests>=2.25.1
40
+ Requires-Dist: python-dotenv>=0.15.0
41
+ Requires-Dist: requests-pkcs12>=1.25
42
+ Provides-Extra: dev
43
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
44
+ Requires-Dist: pytest-mock>=3.6.1; extra == "dev"
45
+ Requires-Dist: build>=1.2.2.post1; extra == "dev"
46
+ Requires-Dist: twine>=6.1.0; extra == "dev"
47
+ Requires-Dist: ruff>=0.4.2; extra == "dev"
48
+ Dynamic: license-file
49
+
50
+ # pypix-api
51
+
52
+ Biblioteca em Python para comunicação com APIs bancárias, focada na integração com o PIX.
53
+
54
+ ## Sumário
55
+
56
+ - [pypix-api](#pypix-api)
57
+ - [Sumário](#sumário)
58
+ - [Visão Geral](#visão-geral)
59
+ - [Instalação](#instalação)
60
+ - [Exemplo de Uso](#exemplo-de-uso)
61
+ - [Estrutura do Projeto](#estrutura-do-projeto)
62
+ - [Configuração](#configuração)
63
+ - [Testes](#testes)
64
+ - [Contribuição](#contribuição)
65
+ - [Licença](#licença)
66
+
67
+ ## Visão Geral
68
+
69
+ O `pypix-api` facilita a integração de sistemas Python com APIs bancárias brasileiras, com ênfase no ecossistema do PIX. A biblioteca abstrai autenticação, comunicação segura (MTLS/OAuth2), e operações comuns de bancos como Banco do Brasil e Sicoob.
70
+
71
+ ## Instalação
72
+
73
+ Recomenda-se o uso de ambiente virtual.
74
+
75
+ ```bash
76
+ pip install .
77
+ ```
78
+
79
+ Ou, para desenvolvimento:
80
+
81
+ ```bash
82
+ git clone https://github.com/seu-usuario/pypix-api.git
83
+ cd pypix-api
84
+ pip install -e .
85
+ ```
86
+
87
+ ## Exemplo de Uso
88
+
89
+ ```python
90
+ from pypix_api.banks.bb import BancoDoBrasil
91
+
92
+ # Instanciação do banco (OAuth2 é inicializado internamente)
93
+ bb = BancoDoBrasil(
94
+ client_id="SEU_CLIENT_ID",
95
+ client_secret="SEU_CLIENT_SECRET",
96
+ cert_path="caminho/do/certificado.pem",
97
+ key_path="caminho/da/chave.key"
98
+ )
99
+
100
+ # Exemplo: Cobrança com Vencimento
101
+ payload = {
102
+ "calendario": {
103
+ "dataDeVencimento": "2025-12-31",
104
+ "validadeAposVencimento": 30
105
+ },
106
+ "loc": {
107
+ "id": 789
108
+ },
109
+ "devedor": {
110
+ "logradouro": "Alameda Souza, Numero 80, Bairro Braz",
111
+ "cidade": "Recife",
112
+ "uf": "PE",
113
+ "cep": "70011750",
114
+ "cpf": "12345678909",
115
+ "nome": "Francisco da Silva"
116
+ },
117
+ "valor": {
118
+ "original": "123.45",
119
+ "multa": {
120
+ "modalidade": "2",
121
+ "valorPerc": "15.00"
122
+ },
123
+ "juros": {
124
+ "modalidade": "2",
125
+ "valorPerc": "2.00"
126
+ },
127
+ "desconto": {
128
+ "modalidade": "1",
129
+ "descontoDataFixa": [
130
+ {
131
+ "data": "2025-11-30",
132
+ "valorPerc": "30.00"
133
+ }
134
+ ]
135
+ }
136
+ },
137
+ "chave": "5f84a4c5-c5cb-4599-9f13-7eb4d419dacc",
138
+ "solicitacaoPagador": "Cobrança dos serviços prestados."
139
+ }
140
+ cobv = bb.criar_cobv(txid="uuid-unico", body=payload)
141
+ print(cobv)
142
+ ```
143
+
144
+ ## Estrutura do Projeto
145
+
146
+ ```
147
+ pypix_api/
148
+ ├── auth/ # Autenticação (MTLS, OAuth2)
149
+ ├── banks/ # Integrações com bancos (BB, Sicoob, métodos PIX)
150
+ ├── models/ # Modelos de dados do PIX
151
+ ├── utils/ # Utilitários (HTTP client, helpers)
152
+ tests/ # Testes automatizados
153
+ openapi.yaml # Especificação OpenAPI (se aplicável)
154
+ pyproject.toml # Configuração do projeto Python
155
+ Makefile # Comandos úteis para desenvolvimento
156
+ .env.exemplo # Exemplo de variáveis de ambiente
157
+ ```
158
+
159
+ ## Configuração
160
+
161
+ Crie um arquivo `.env` baseado em `.env.exemplo` com as credenciais e configurações necessárias para autenticação e acesso às APIs bancárias.
162
+
163
+ ## Testes
164
+
165
+ Para rodar os testes automatizados:
166
+
167
+ ```bash
168
+ make test
169
+ ```
170
+ ou diretamente com pytest:
171
+ ```bash
172
+ pytest
173
+ ```
174
+
175
+ ## Contribuição
176
+
177
+ Contribuições são bem-vindas! Siga os passos:
178
+
179
+ 1. Fork este repositório
180
+ 2. Crie uma branch (`git checkout -b feature/nova-funcionalidade`)
181
+ 3. Commit suas alterações (`git commit -am 'Adiciona nova funcionalidade'`)
182
+ 4. Push para a branch (`git push origin feature/nova-funcionalidade`)
183
+ 5. Abra um Pull Request
184
+
185
+ ## Licença
186
+
187
+ Este projeto está licenciado sob os termos da licença MIT.
@@ -0,0 +1,21 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ pypix_api/__init__.py
5
+ pypix_api.egg-info/PKG-INFO
6
+ pypix_api.egg-info/SOURCES.txt
7
+ pypix_api.egg-info/dependency_links.txt
8
+ pypix_api.egg-info/requires.txt
9
+ pypix_api.egg-info/top_level.txt
10
+ pypix_api/auth/mtls.py
11
+ pypix_api/auth/oauth2.py
12
+ pypix_api/banks/base.py
13
+ pypix_api/banks/bb.py
14
+ pypix_api/banks/cobv_methods.py
15
+ pypix_api/banks/sicoob.py
16
+ pypix_api/models/pix.py
17
+ pypix_api/utils/http_client.py
18
+ tests/test_auth.py
19
+ tests/test_banks.py
20
+ tests/test_models.py
21
+ tests/test_utils.py
@@ -0,0 +1,10 @@
1
+ requests>=2.25.1
2
+ python-dotenv>=0.15.0
3
+ requests-pkcs12>=1.25
4
+
5
+ [dev]
6
+ pytest>=7.0.0
7
+ pytest-mock>=3.6.1
8
+ build>=1.2.2.post1
9
+ twine>=6.1.0
10
+ ruff>=0.4.2
@@ -0,0 +1 @@
1
+ pypix_api
@@ -0,0 +1,77 @@
1
+ [project]
2
+ name = "pypix-api"
3
+ version = "0.0.3"
4
+ description = "Biblioteca em Python para comunicação com APIs bancárias focada na integração com o PIX"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ authors = [
8
+ { name = "Fábio Thomaz", email = "fabio@ladder.dev.br" }
9
+ ]
10
+ license.file = "LICENSE"
11
+ keywords = ["pix", "api", "banco", "pagamento", "brasil"]
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Operating System :: OS Independent",
16
+ "Intended Audience :: Developers",
17
+ "Topic :: Software Development :: Libraries :: Python Modules"
18
+ ]
19
+ dependencies = [
20
+ "requests>=2.25.1",
21
+ "python-dotenv>=0.15.0",
22
+ "requests-pkcs12>=1.25"
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/laddertech/pypix-api"
27
+ Repository = "https://github.com/laddertech/pypix-api"
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "pytest>=7.0.0",
31
+ "pytest-mock>=3.6.1",
32
+ "build>=1.2.2.post1",
33
+ "twine>=6.1.0",
34
+ "ruff>=0.4.2"
35
+ ]
36
+
37
+ [build-system]
38
+ requires = ["setuptools>=61.0", "wheel"]
39
+ build-backend = "setuptools.build_meta"
40
+
41
+ [tool.ruff]
42
+ # Configurações base do Ruff
43
+ line-length = 88
44
+ exclude = [
45
+ ".venv",
46
+ "build",
47
+ "dist",
48
+ "__pycache__",
49
+ ".pytest_cache",
50
+ ".ruff_cache",
51
+ ]
52
+
53
+ [tool.ruff.lint]
54
+ select = [
55
+ "E", # pycodestyle errors
56
+ "W", # pycodestyle warnings
57
+ "F", # pyflakes
58
+ "I", # isort
59
+ "B", # flake8-bugbear
60
+ "C", # flake8-comprehensions
61
+ "UP", # pyupgrade
62
+ "YTT", # flake8-2020
63
+ "ANN", # flake8-annotations
64
+ "S", # flake8-bandit
65
+ "RUF", # Ruff-specific rules
66
+ ]
67
+ ignore = [
68
+ "E501", # Line too long (handled by black)
69
+ "S101", # Use of print (handled by black)
70
+ ]
71
+
72
+ # Configurações específicas
73
+ [tool.ruff.lint.isort]
74
+ known-first-party = ["pypix_api"]
75
+
76
+ [tool.ruff.format]
77
+ quote-style = "single"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,23 @@
1
+ from pypix_api.auth.oauth2 import OAuth2Client
2
+
3
+ def test_oauth2client_init(monkeypatch):
4
+ class DummySession:
5
+ pass
6
+ monkeypatch.setattr("pypix_api.auth.oauth2.get_session_with_mtls", lambda *a, **kw: DummySession())
7
+ client = OAuth2Client(
8
+ token_url="token_url",
9
+ client_id="client_id",
10
+ cert="cert_path",
11
+ pvk="key_path",
12
+ cert_pfx="cert.pfx",
13
+ pwd_pfx="senha",
14
+ sandbox_mode=False,
15
+ )
16
+ assert client.client_id == "client_id"
17
+ assert client.cert == "cert_path"
18
+ assert client.pvk == "key_path"
19
+ assert client.cert_pfx == "cert.pfx"
20
+ assert client.pwd_pfx == "senha"
21
+ assert client.token_url == "token_url"
22
+ assert client.sandbox_mode is False
23
+ assert isinstance(client.session, DummySession)
@@ -0,0 +1,47 @@
1
+ import pytest
2
+ from unittest.mock import patch, MagicMock
3
+ from pypix_api.banks.base import BankPixAPIBase
4
+ from pypix_api.banks.bb import BBPixAPI
5
+ from pypix_api.banks.sicoob import SicoobPixAPI
6
+ from pypix_api.banks.cobv_methods import CobVMethods
7
+
8
+ class DummyCobVMethods(CobVMethods):
9
+ def criar_cobv(self, txid, body):
10
+ return {"txid": txid, "body": body}
11
+ def revisar_cobv(self, txid, body):
12
+ return {"txid": txid, "body": body}
13
+ def consultar_cobv(self, txid):
14
+ return {"txid": txid}
15
+ def listar_cobv(self):
16
+ return []
17
+
18
+ def test_bankpixapibase_init():
19
+ class DummyBank(BankPixAPIBase, DummyCobVMethods):
20
+ BASE_URL = "https://dummy"
21
+ TOKEN_URL = "https://dummy/token"
22
+ SCOPES = ["dummy.scope"]
23
+
24
+ import sys
25
+ with patch("pypix_api.banks.base.OAuth2Client", MagicMock()), \
26
+ patch("pypix_api.auth.mtls.get_session_with_mtls", MagicMock(return_value=object())):
27
+ bank = DummyBank("id", "secret", "cert", "key")
28
+ assert hasattr(bank, "session")
29
+ assert hasattr(bank, "oauth")
30
+
31
+ def test_bb_pix_api_inheritance():
32
+ with patch("pypix_api.banks.base.OAuth2Client", MagicMock()), \
33
+ patch("pypix_api.auth.mtls.get_session_with_mtls", MagicMock(return_value=object())):
34
+ api = BBPixAPI("id", "secret", "cert", "key")
35
+ assert isinstance(api, BankPixAPIBase)
36
+
37
+ def test_sicoob_pix_api_inheritance():
38
+ with patch("pypix_api.banks.base.OAuth2Client", MagicMock()), \
39
+ patch("pypix_api.auth.mtls.get_session_with_mtls", MagicMock(return_value=object())):
40
+ api = SicoobPixAPI("id", "secret", "cert", "key")
41
+ assert isinstance(api, BankPixAPIBase)
42
+
43
+ def test_cobv_methods_criar():
44
+ cobv = DummyCobVMethods()
45
+ result = cobv.criar_cobv("123", {"valor": 10})
46
+ assert result["txid"] == "123"
47
+ assert result["body"]["valor"] == 10
@@ -0,0 +1,8 @@
1
+ import pytest
2
+ from pypix_api.models.pix import PixCobranca
3
+
4
+ def test_pix_cobranca_init():
5
+ cobranca = PixCobranca(txid="abc123", valor=100.0, status="ATIVA", chave="minha-chave")
6
+ assert cobranca.txid == "abc123"
7
+ assert cobranca.valor == 100.0
8
+ assert cobranca.status == "ATIVA"
@@ -0,0 +1,20 @@
1
+ import pytest
2
+ from pypix_api.utils.http_client import get
3
+
4
+ def test_get(monkeypatch):
5
+ class DummyResponse:
6
+ def __init__(self):
7
+ self.status_code = 200
8
+ self.text = "ok"
9
+ def json(self):
10
+ return {"result": "ok"}
11
+ def dummy_requests_get(url, headers=None, cert=None):
12
+ assert url == "http://test"
13
+ assert headers == {"Authorization": "Bearer token"}
14
+ assert cert == "cert.pem"
15
+ return DummyResponse()
16
+ monkeypatch.setattr("requests.get", dummy_requests_get)
17
+ response = get("http://test", headers={"Authorization": "Bearer token"}, cert="cert.pem")
18
+ assert response.status_code == 200
19
+ assert response.text == "ok"
20
+ assert response.json() == {"result": "ok"}