nxgate-sdk-python 1.0.0__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.
- nxgate_sdk_python-1.0.0/LICENSE +21 -0
- nxgate_sdk_python-1.0.0/PKG-INFO +301 -0
- nxgate_sdk_python-1.0.0/README.md +275 -0
- nxgate_sdk_python-1.0.0/nxgate/__init__.py +59 -0
- nxgate_sdk_python-1.0.0/nxgate/auth.py +105 -0
- nxgate_sdk_python-1.0.0/nxgate/client.py +251 -0
- nxgate_sdk_python-1.0.0/nxgate/errors.py +50 -0
- nxgate_sdk_python-1.0.0/nxgate/hmac_signer.py +56 -0
- nxgate_sdk_python-1.0.0/nxgate/types.py +297 -0
- nxgate_sdk_python-1.0.0/nxgate/webhook.py +48 -0
- nxgate_sdk_python-1.0.0/nxgate_sdk_python.egg-info/PKG-INFO +301 -0
- nxgate_sdk_python-1.0.0/nxgate_sdk_python.egg-info/SOURCES.txt +19 -0
- nxgate_sdk_python-1.0.0/nxgate_sdk_python.egg-info/dependency_links.txt +1 -0
- nxgate_sdk_python-1.0.0/nxgate_sdk_python.egg-info/top_level.txt +1 -0
- nxgate_sdk_python-1.0.0/pyproject.toml +46 -0
- nxgate_sdk_python-1.0.0/setup.cfg +4 -0
- nxgate_sdk_python-1.0.0/tests/test_auth.py +196 -0
- nxgate_sdk_python-1.0.0/tests/test_client.py +386 -0
- nxgate_sdk_python-1.0.0/tests/test_errors.py +66 -0
- nxgate_sdk_python-1.0.0/tests/test_hmac.py +66 -0
- nxgate_sdk_python-1.0.0/tests/test_webhook.py +94 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 NXGATE
|
|
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,301 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nxgate-sdk-python
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: SDK oficial da NXGATE para integração com a API PIX
|
|
5
|
+
Author-email: NXGATE <suporte@nxgate.com.br>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/nxgate/nxgate-sdk-python
|
|
8
|
+
Project-URL: Documentation, https://github.com/nxgate/nxgate-sdk-python#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/nxgate/nxgate-sdk-python
|
|
10
|
+
Keywords: nxgate,pix,pagamentos,qrcode,sdk
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# NXGATE PIX SDK para Python
|
|
28
|
+
|
|
29
|
+
SDK oficial da NXGATE para integração com a API PIX. Permite gerar cobranças (cash-in), realizar saques (cash-out), consultar saldo e transações, tudo com tipagem completa e zero dependências externas.
|
|
30
|
+
|
|
31
|
+
## Requisitos
|
|
32
|
+
|
|
33
|
+
- Python 3.10 ou superior
|
|
34
|
+
- Sem dependências externas (usa apenas a biblioteca padrão)
|
|
35
|
+
|
|
36
|
+
## Instalação
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install nxgate
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Ou instale diretamente do repositório:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install git+https://github.com/nxgate/sdk-python.git
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Início Rápido
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from nxgate import NXGate, NXGateWebhook
|
|
52
|
+
|
|
53
|
+
nx = NXGate(
|
|
54
|
+
client_id="nxgate_xxx",
|
|
55
|
+
client_secret="secret",
|
|
56
|
+
hmac_secret="opcional", # opcional - quando informado, todas as requisições são assinadas com HMAC-SHA256
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Funcionalidades
|
|
61
|
+
|
|
62
|
+
### Gerar cobrança PIX (Cash-in)
|
|
63
|
+
|
|
64
|
+
Gera uma cobrança PIX e retorna o QR Code para pagamento.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
charge = nx.pix_generate(
|
|
68
|
+
valor=100.00,
|
|
69
|
+
nome_pagador="João da Silva",
|
|
70
|
+
documento_pagador="12345678901",
|
|
71
|
+
webhook="https://meusite.com/webhook",
|
|
72
|
+
descricao="Pedido #1234",
|
|
73
|
+
email_pagador="joao@email.com",
|
|
74
|
+
celular="11999999999",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
print(charge.status) # "ACTIVE"
|
|
78
|
+
print(charge.paymentCode) # código copia-e-cola
|
|
79
|
+
print(charge.idTransaction) # ID da transação
|
|
80
|
+
print(charge.paymentCodeBase64) # QR Code em base64
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### Cobrança com split de pagamento
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
charge = nx.pix_generate(
|
|
87
|
+
valor=200.00,
|
|
88
|
+
nome_pagador="Maria Souza",
|
|
89
|
+
documento_pagador="98765432100",
|
|
90
|
+
split_users=[
|
|
91
|
+
{"username": "loja_a", "percentage": 70.0},
|
|
92
|
+
{"username": "loja_b", "percentage": 30.0},
|
|
93
|
+
],
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Saque PIX (Cash-out)
|
|
98
|
+
|
|
99
|
+
Realiza uma transferência PIX para uma chave destino.
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
withdrawal = nx.pix_withdraw(
|
|
103
|
+
valor=50.00,
|
|
104
|
+
chave_pix="joao@email.com",
|
|
105
|
+
tipo_chave="EMAIL", # CPF | CNPJ | PHONE | EMAIL | RANDOM
|
|
106
|
+
webhook="https://meusite.com/webhook",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
print(withdrawal.status) # "PROCESSING"
|
|
110
|
+
print(withdrawal.internalreference) # referência interna
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Consultar saldo
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
balance = nx.get_balance()
|
|
117
|
+
|
|
118
|
+
print(balance.balance) # saldo total
|
|
119
|
+
print(balance.blocked) # saldo bloqueado
|
|
120
|
+
print(balance.available) # saldo disponível
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Consultar transação
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
tx = nx.get_transaction(type="cash-in", txid="px_xxx")
|
|
127
|
+
|
|
128
|
+
print(tx.idTransaction) # ID da transação
|
|
129
|
+
print(tx.status) # status atual
|
|
130
|
+
print(tx.amount) # valor
|
|
131
|
+
print(tx.paidAt) # data do pagamento
|
|
132
|
+
print(tx.endToEnd) # identificador end-to-end
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Webhooks
|
|
136
|
+
|
|
137
|
+
O SDK fornece um parser para eventos recebidos via webhook.
|
|
138
|
+
|
|
139
|
+
### Recebendo eventos (exemplo com Flask)
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from flask import Flask, request, jsonify
|
|
143
|
+
from nxgate import NXGateWebhook, NXGateError
|
|
144
|
+
from nxgate.types import CashInEvent, CashOutEvent
|
|
145
|
+
|
|
146
|
+
app = Flask(__name__)
|
|
147
|
+
|
|
148
|
+
@app.route("/webhook", methods=["POST"])
|
|
149
|
+
def webhook():
|
|
150
|
+
try:
|
|
151
|
+
event = NXGateWebhook.parse(request.json)
|
|
152
|
+
except NXGateError as e:
|
|
153
|
+
return jsonify({"error": str(e)}), 400
|
|
154
|
+
|
|
155
|
+
if isinstance(event, CashInEvent):
|
|
156
|
+
print(f"Cash-in: {event.type}")
|
|
157
|
+
print(f" Valor: R$ {event.data.amount:.2f}")
|
|
158
|
+
print(f" Pagador: {event.data.debtor_name}")
|
|
159
|
+
print(f" TX ID: {event.data.tx_id}")
|
|
160
|
+
print(f" Status: {event.data.status}")
|
|
161
|
+
|
|
162
|
+
elif isinstance(event, CashOutEvent):
|
|
163
|
+
print(f"Cash-out: {event.type}")
|
|
164
|
+
print(f" Valor: R$ {event.amount:.2f}")
|
|
165
|
+
print(f" Chave: {event.key}")
|
|
166
|
+
if event.error:
|
|
167
|
+
print(f" Erro: {event.error}")
|
|
168
|
+
|
|
169
|
+
return jsonify({"ok": True})
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Tipos de evento
|
|
173
|
+
|
|
174
|
+
**Cash-in:**
|
|
175
|
+
- `QR_CODE_COPY_AND_PASTE_PAID` - pagamento confirmado
|
|
176
|
+
- `QR_CODE_COPY_AND_PASTE_REFUNDED` - pagamento devolvido
|
|
177
|
+
|
|
178
|
+
**Cash-out:**
|
|
179
|
+
- `PIX_CASHOUT_SUCCESS` - saque realizado com sucesso
|
|
180
|
+
- `PIX_CASHOUT_ERROR` - erro no saque
|
|
181
|
+
- `PIX_CASHOUT_REFUNDED` - saque devolvido
|
|
182
|
+
|
|
183
|
+
## Assinatura HMAC
|
|
184
|
+
|
|
185
|
+
Quando o parâmetro `hmac_secret` é informado na inicialização do cliente, todas as requisições são automaticamente assinadas com HMAC-SHA256. Os seguintes headers são adicionados:
|
|
186
|
+
|
|
187
|
+
| Header | Descrição |
|
|
188
|
+
|--------|-----------|
|
|
189
|
+
| `X-Client-ID` | Seu `client_id` |
|
|
190
|
+
| `X-HMAC-Signature` | Assinatura HMAC-SHA256 em base64 |
|
|
191
|
+
| `X-HMAC-Timestamp` | Timestamp ISO 8601 |
|
|
192
|
+
| `X-HMAC-Nonce` | Valor único por requisição |
|
|
193
|
+
|
|
194
|
+
A assinatura é gerada sobre a string canônica:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
METHOD\nPATH\nTIMESTAMP\nNONCE\nBODY
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Gerenciamento de Token
|
|
201
|
+
|
|
202
|
+
O SDK gerencia automaticamente o token OAuth2:
|
|
203
|
+
|
|
204
|
+
- O token é obtido na primeira requisição
|
|
205
|
+
- É mantido em cache enquanto válido
|
|
206
|
+
- É renovado automaticamente 60 segundos antes de expirar
|
|
207
|
+
- Em caso de falha na autenticação, `NXGateAuthError` é lançado
|
|
208
|
+
|
|
209
|
+
## Tratamento de Erros
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
from nxgate import NXGate, NXGateError
|
|
213
|
+
from nxgate.errors import NXGateAuthError, NXGateTimeoutError, NXGateRetryError
|
|
214
|
+
|
|
215
|
+
nx = NXGate(client_id="xxx", client_secret="yyy")
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
charge = nx.pix_generate(
|
|
219
|
+
valor=100.00,
|
|
220
|
+
nome_pagador="Teste",
|
|
221
|
+
documento_pagador="00000000000",
|
|
222
|
+
)
|
|
223
|
+
except NXGateAuthError as e:
|
|
224
|
+
print(f"Erro de autenticação: {e}")
|
|
225
|
+
print(f"Status HTTP: {e.status_code}")
|
|
226
|
+
except NXGateTimeoutError as e:
|
|
227
|
+
print(f"Timeout: {e}")
|
|
228
|
+
except NXGateRetryError as e:
|
|
229
|
+
print(f"Todas as tentativas falharam: {e}")
|
|
230
|
+
except NXGateError as e:
|
|
231
|
+
print(f"Erro da API: {e}")
|
|
232
|
+
print(f"Título: {e.title}")
|
|
233
|
+
print(f"Código: {e.code}")
|
|
234
|
+
print(f"Descrição: {e.description}")
|
|
235
|
+
print(f"Status HTTP: {e.status_code}")
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Hierarquia de exceções
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
Exception
|
|
242
|
+
└── NXGateError
|
|
243
|
+
├── NXGateAuthError # falha na autenticação
|
|
244
|
+
├── NXGateTimeoutError # timeout na requisição
|
|
245
|
+
└── NXGateRetryError # tentativas esgotadas (503)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Retry Automático
|
|
249
|
+
|
|
250
|
+
Requisições que retornam HTTP 503 são automaticamente retentadas com backoff exponencial:
|
|
251
|
+
|
|
252
|
+
- Máximo de 2 retentativas (3 tentativas no total)
|
|
253
|
+
- Delay entre tentativas: 1s, 2s
|
|
254
|
+
- Se todas as tentativas falharem, `NXGateRetryError` é lançado
|
|
255
|
+
|
|
256
|
+
## Referência da API
|
|
257
|
+
|
|
258
|
+
### `NXGate(client_id, client_secret, hmac_secret=None, *, base_url, timeout)`
|
|
259
|
+
|
|
260
|
+
| Parâmetro | Tipo | Obrigatório | Descrição |
|
|
261
|
+
|-----------|------|-------------|-----------|
|
|
262
|
+
| `client_id` | `str` | Sim | Seu client_id NXGATE |
|
|
263
|
+
| `client_secret` | `str` | Sim | Seu client_secret NXGATE |
|
|
264
|
+
| `hmac_secret` | `str \| None` | Não | Secret para assinatura HMAC |
|
|
265
|
+
| `base_url` | `str` | Não | URL base da API (padrão: `https://api.nxgate.com.br`) |
|
|
266
|
+
| `timeout` | `int` | Não | Timeout em segundos (padrão: `30`) |
|
|
267
|
+
|
|
268
|
+
### Métodos
|
|
269
|
+
|
|
270
|
+
| Método | Retorno | Descrição |
|
|
271
|
+
|--------|---------|-----------|
|
|
272
|
+
| `pix_generate(...)` | `PixGenerateResponse` | Gera cobrança PIX |
|
|
273
|
+
| `pix_withdraw(...)` | `PixWithdrawResponse` | Realiza saque PIX |
|
|
274
|
+
| `get_balance()` | `BalanceResponse` | Consulta saldo |
|
|
275
|
+
| `get_transaction(type, txid)` | `TransactionResponse` | Consulta transação |
|
|
276
|
+
|
|
277
|
+
## Desenvolvimento
|
|
278
|
+
|
|
279
|
+
### Executar testes
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
pip install pytest
|
|
283
|
+
pytest
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Estrutura do projeto
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
nxgate/
|
|
290
|
+
├── __init__.py # exports públicos
|
|
291
|
+
├── client.py # classe NXGate
|
|
292
|
+
├── auth.py # gerenciamento de token
|
|
293
|
+
├── hmac_signer.py # assinatura HMAC
|
|
294
|
+
├── webhook.py # parser de webhook
|
|
295
|
+
├── errors.py # exceções
|
|
296
|
+
└── types.py # dataclasses tipadas
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Licença
|
|
300
|
+
|
|
301
|
+
MIT - veja o arquivo [LICENSE](LICENSE) para detalhes.
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# NXGATE PIX SDK para Python
|
|
2
|
+
|
|
3
|
+
SDK oficial da NXGATE para integração com a API PIX. Permite gerar cobranças (cash-in), realizar saques (cash-out), consultar saldo e transações, tudo com tipagem completa e zero dependências externas.
|
|
4
|
+
|
|
5
|
+
## Requisitos
|
|
6
|
+
|
|
7
|
+
- Python 3.10 ou superior
|
|
8
|
+
- Sem dependências externas (usa apenas a biblioteca padrão)
|
|
9
|
+
|
|
10
|
+
## Instalação
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install nxgate
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Ou instale diretamente do repositório:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install git+https://github.com/nxgate/sdk-python.git
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Início Rápido
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from nxgate import NXGate, NXGateWebhook
|
|
26
|
+
|
|
27
|
+
nx = NXGate(
|
|
28
|
+
client_id="nxgate_xxx",
|
|
29
|
+
client_secret="secret",
|
|
30
|
+
hmac_secret="opcional", # opcional - quando informado, todas as requisições são assinadas com HMAC-SHA256
|
|
31
|
+
)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Funcionalidades
|
|
35
|
+
|
|
36
|
+
### Gerar cobrança PIX (Cash-in)
|
|
37
|
+
|
|
38
|
+
Gera uma cobrança PIX e retorna o QR Code para pagamento.
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
charge = nx.pix_generate(
|
|
42
|
+
valor=100.00,
|
|
43
|
+
nome_pagador="João da Silva",
|
|
44
|
+
documento_pagador="12345678901",
|
|
45
|
+
webhook="https://meusite.com/webhook",
|
|
46
|
+
descricao="Pedido #1234",
|
|
47
|
+
email_pagador="joao@email.com",
|
|
48
|
+
celular="11999999999",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
print(charge.status) # "ACTIVE"
|
|
52
|
+
print(charge.paymentCode) # código copia-e-cola
|
|
53
|
+
print(charge.idTransaction) # ID da transação
|
|
54
|
+
print(charge.paymentCodeBase64) # QR Code em base64
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### Cobrança com split de pagamento
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
charge = nx.pix_generate(
|
|
61
|
+
valor=200.00,
|
|
62
|
+
nome_pagador="Maria Souza",
|
|
63
|
+
documento_pagador="98765432100",
|
|
64
|
+
split_users=[
|
|
65
|
+
{"username": "loja_a", "percentage": 70.0},
|
|
66
|
+
{"username": "loja_b", "percentage": 30.0},
|
|
67
|
+
],
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Saque PIX (Cash-out)
|
|
72
|
+
|
|
73
|
+
Realiza uma transferência PIX para uma chave destino.
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
withdrawal = nx.pix_withdraw(
|
|
77
|
+
valor=50.00,
|
|
78
|
+
chave_pix="joao@email.com",
|
|
79
|
+
tipo_chave="EMAIL", # CPF | CNPJ | PHONE | EMAIL | RANDOM
|
|
80
|
+
webhook="https://meusite.com/webhook",
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
print(withdrawal.status) # "PROCESSING"
|
|
84
|
+
print(withdrawal.internalreference) # referência interna
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Consultar saldo
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
balance = nx.get_balance()
|
|
91
|
+
|
|
92
|
+
print(balance.balance) # saldo total
|
|
93
|
+
print(balance.blocked) # saldo bloqueado
|
|
94
|
+
print(balance.available) # saldo disponível
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Consultar transação
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
tx = nx.get_transaction(type="cash-in", txid="px_xxx")
|
|
101
|
+
|
|
102
|
+
print(tx.idTransaction) # ID da transação
|
|
103
|
+
print(tx.status) # status atual
|
|
104
|
+
print(tx.amount) # valor
|
|
105
|
+
print(tx.paidAt) # data do pagamento
|
|
106
|
+
print(tx.endToEnd) # identificador end-to-end
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Webhooks
|
|
110
|
+
|
|
111
|
+
O SDK fornece um parser para eventos recebidos via webhook.
|
|
112
|
+
|
|
113
|
+
### Recebendo eventos (exemplo com Flask)
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from flask import Flask, request, jsonify
|
|
117
|
+
from nxgate import NXGateWebhook, NXGateError
|
|
118
|
+
from nxgate.types import CashInEvent, CashOutEvent
|
|
119
|
+
|
|
120
|
+
app = Flask(__name__)
|
|
121
|
+
|
|
122
|
+
@app.route("/webhook", methods=["POST"])
|
|
123
|
+
def webhook():
|
|
124
|
+
try:
|
|
125
|
+
event = NXGateWebhook.parse(request.json)
|
|
126
|
+
except NXGateError as e:
|
|
127
|
+
return jsonify({"error": str(e)}), 400
|
|
128
|
+
|
|
129
|
+
if isinstance(event, CashInEvent):
|
|
130
|
+
print(f"Cash-in: {event.type}")
|
|
131
|
+
print(f" Valor: R$ {event.data.amount:.2f}")
|
|
132
|
+
print(f" Pagador: {event.data.debtor_name}")
|
|
133
|
+
print(f" TX ID: {event.data.tx_id}")
|
|
134
|
+
print(f" Status: {event.data.status}")
|
|
135
|
+
|
|
136
|
+
elif isinstance(event, CashOutEvent):
|
|
137
|
+
print(f"Cash-out: {event.type}")
|
|
138
|
+
print(f" Valor: R$ {event.amount:.2f}")
|
|
139
|
+
print(f" Chave: {event.key}")
|
|
140
|
+
if event.error:
|
|
141
|
+
print(f" Erro: {event.error}")
|
|
142
|
+
|
|
143
|
+
return jsonify({"ok": True})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Tipos de evento
|
|
147
|
+
|
|
148
|
+
**Cash-in:**
|
|
149
|
+
- `QR_CODE_COPY_AND_PASTE_PAID` - pagamento confirmado
|
|
150
|
+
- `QR_CODE_COPY_AND_PASTE_REFUNDED` - pagamento devolvido
|
|
151
|
+
|
|
152
|
+
**Cash-out:**
|
|
153
|
+
- `PIX_CASHOUT_SUCCESS` - saque realizado com sucesso
|
|
154
|
+
- `PIX_CASHOUT_ERROR` - erro no saque
|
|
155
|
+
- `PIX_CASHOUT_REFUNDED` - saque devolvido
|
|
156
|
+
|
|
157
|
+
## Assinatura HMAC
|
|
158
|
+
|
|
159
|
+
Quando o parâmetro `hmac_secret` é informado na inicialização do cliente, todas as requisições são automaticamente assinadas com HMAC-SHA256. Os seguintes headers são adicionados:
|
|
160
|
+
|
|
161
|
+
| Header | Descrição |
|
|
162
|
+
|--------|-----------|
|
|
163
|
+
| `X-Client-ID` | Seu `client_id` |
|
|
164
|
+
| `X-HMAC-Signature` | Assinatura HMAC-SHA256 em base64 |
|
|
165
|
+
| `X-HMAC-Timestamp` | Timestamp ISO 8601 |
|
|
166
|
+
| `X-HMAC-Nonce` | Valor único por requisição |
|
|
167
|
+
|
|
168
|
+
A assinatura é gerada sobre a string canônica:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
METHOD\nPATH\nTIMESTAMP\nNONCE\nBODY
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Gerenciamento de Token
|
|
175
|
+
|
|
176
|
+
O SDK gerencia automaticamente o token OAuth2:
|
|
177
|
+
|
|
178
|
+
- O token é obtido na primeira requisição
|
|
179
|
+
- É mantido em cache enquanto válido
|
|
180
|
+
- É renovado automaticamente 60 segundos antes de expirar
|
|
181
|
+
- Em caso de falha na autenticação, `NXGateAuthError` é lançado
|
|
182
|
+
|
|
183
|
+
## Tratamento de Erros
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from nxgate import NXGate, NXGateError
|
|
187
|
+
from nxgate.errors import NXGateAuthError, NXGateTimeoutError, NXGateRetryError
|
|
188
|
+
|
|
189
|
+
nx = NXGate(client_id="xxx", client_secret="yyy")
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
charge = nx.pix_generate(
|
|
193
|
+
valor=100.00,
|
|
194
|
+
nome_pagador="Teste",
|
|
195
|
+
documento_pagador="00000000000",
|
|
196
|
+
)
|
|
197
|
+
except NXGateAuthError as e:
|
|
198
|
+
print(f"Erro de autenticação: {e}")
|
|
199
|
+
print(f"Status HTTP: {e.status_code}")
|
|
200
|
+
except NXGateTimeoutError as e:
|
|
201
|
+
print(f"Timeout: {e}")
|
|
202
|
+
except NXGateRetryError as e:
|
|
203
|
+
print(f"Todas as tentativas falharam: {e}")
|
|
204
|
+
except NXGateError as e:
|
|
205
|
+
print(f"Erro da API: {e}")
|
|
206
|
+
print(f"Título: {e.title}")
|
|
207
|
+
print(f"Código: {e.code}")
|
|
208
|
+
print(f"Descrição: {e.description}")
|
|
209
|
+
print(f"Status HTTP: {e.status_code}")
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Hierarquia de exceções
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
Exception
|
|
216
|
+
└── NXGateError
|
|
217
|
+
├── NXGateAuthError # falha na autenticação
|
|
218
|
+
├── NXGateTimeoutError # timeout na requisição
|
|
219
|
+
└── NXGateRetryError # tentativas esgotadas (503)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Retry Automático
|
|
223
|
+
|
|
224
|
+
Requisições que retornam HTTP 503 são automaticamente retentadas com backoff exponencial:
|
|
225
|
+
|
|
226
|
+
- Máximo de 2 retentativas (3 tentativas no total)
|
|
227
|
+
- Delay entre tentativas: 1s, 2s
|
|
228
|
+
- Se todas as tentativas falharem, `NXGateRetryError` é lançado
|
|
229
|
+
|
|
230
|
+
## Referência da API
|
|
231
|
+
|
|
232
|
+
### `NXGate(client_id, client_secret, hmac_secret=None, *, base_url, timeout)`
|
|
233
|
+
|
|
234
|
+
| Parâmetro | Tipo | Obrigatório | Descrição |
|
|
235
|
+
|-----------|------|-------------|-----------|
|
|
236
|
+
| `client_id` | `str` | Sim | Seu client_id NXGATE |
|
|
237
|
+
| `client_secret` | `str` | Sim | Seu client_secret NXGATE |
|
|
238
|
+
| `hmac_secret` | `str \| None` | Não | Secret para assinatura HMAC |
|
|
239
|
+
| `base_url` | `str` | Não | URL base da API (padrão: `https://api.nxgate.com.br`) |
|
|
240
|
+
| `timeout` | `int` | Não | Timeout em segundos (padrão: `30`) |
|
|
241
|
+
|
|
242
|
+
### Métodos
|
|
243
|
+
|
|
244
|
+
| Método | Retorno | Descrição |
|
|
245
|
+
|--------|---------|-----------|
|
|
246
|
+
| `pix_generate(...)` | `PixGenerateResponse` | Gera cobrança PIX |
|
|
247
|
+
| `pix_withdraw(...)` | `PixWithdrawResponse` | Realiza saque PIX |
|
|
248
|
+
| `get_balance()` | `BalanceResponse` | Consulta saldo |
|
|
249
|
+
| `get_transaction(type, txid)` | `TransactionResponse` | Consulta transação |
|
|
250
|
+
|
|
251
|
+
## Desenvolvimento
|
|
252
|
+
|
|
253
|
+
### Executar testes
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
pip install pytest
|
|
257
|
+
pytest
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Estrutura do projeto
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
nxgate/
|
|
264
|
+
├── __init__.py # exports públicos
|
|
265
|
+
├── client.py # classe NXGate
|
|
266
|
+
├── auth.py # gerenciamento de token
|
|
267
|
+
├── hmac_signer.py # assinatura HMAC
|
|
268
|
+
├── webhook.py # parser de webhook
|
|
269
|
+
├── errors.py # exceções
|
|
270
|
+
└── types.py # dataclasses tipadas
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Licença
|
|
274
|
+
|
|
275
|
+
MIT - veja o arquivo [LICENSE](LICENSE) para detalhes.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""NXGATE PIX SDK for Python.
|
|
2
|
+
|
|
3
|
+
Usage::
|
|
4
|
+
|
|
5
|
+
from nxgate import NXGate, NXGateWebhook
|
|
6
|
+
|
|
7
|
+
nx = NXGate(client_id="...", client_secret="...")
|
|
8
|
+
charge = nx.pix_generate(
|
|
9
|
+
valor=100.00,
|
|
10
|
+
nome_pagador="Joao da Silva",
|
|
11
|
+
documento_pagador="12345678901",
|
|
12
|
+
)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from .client import NXGate
|
|
16
|
+
from .errors import (
|
|
17
|
+
NXGateAuthError,
|
|
18
|
+
NXGateError,
|
|
19
|
+
NXGateRetryError,
|
|
20
|
+
NXGateTimeoutError,
|
|
21
|
+
)
|
|
22
|
+
from .types import (
|
|
23
|
+
BalanceResponse,
|
|
24
|
+
CashInEvent,
|
|
25
|
+
CashInEventData,
|
|
26
|
+
CashOutEvent,
|
|
27
|
+
PixGenerateResponse,
|
|
28
|
+
PixWithdrawResponse,
|
|
29
|
+
SplitUser,
|
|
30
|
+
TokenResponse,
|
|
31
|
+
TransactionResponse,
|
|
32
|
+
WebhookEvent,
|
|
33
|
+
)
|
|
34
|
+
from .webhook import NXGateWebhook
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
# Client
|
|
38
|
+
"NXGate",
|
|
39
|
+
# Webhook
|
|
40
|
+
"NXGateWebhook",
|
|
41
|
+
# Errors
|
|
42
|
+
"NXGateError",
|
|
43
|
+
"NXGateAuthError",
|
|
44
|
+
"NXGateRetryError",
|
|
45
|
+
"NXGateTimeoutError",
|
|
46
|
+
# Types
|
|
47
|
+
"BalanceResponse",
|
|
48
|
+
"CashInEvent",
|
|
49
|
+
"CashInEventData",
|
|
50
|
+
"CashOutEvent",
|
|
51
|
+
"PixGenerateResponse",
|
|
52
|
+
"PixWithdrawResponse",
|
|
53
|
+
"SplitUser",
|
|
54
|
+
"TokenResponse",
|
|
55
|
+
"TransactionResponse",
|
|
56
|
+
"WebhookEvent",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
__version__ = "1.0.0"
|