Python examples
Using requests (client) and Flask (webhook). hmac and hashlib are from the standard library.
Reusable client
import os, requests
BASE_URL = "https://api.internationalfinance.com.br/v1"
class INFIError(Exception):
def __init__(self, status, message):
super().__init__(message)
self.status = status
def infi_request(path, method="GET", body=None, params=None):
headers = {"Authorization": f"Bearer {os.environ['INFI_API_KEY']}"}
if body is not None:
headers["Content-Type"] = "application/json"
res = requests.request(method, f"{BASE_URL}{path}", headers=headers, json=body, params=params)
data = res.json() if res.headers.get("content-type", "").startswith("application/json") else {}
return res.status_code, data
# Create charge
status, data = infi_request("/pix", method="POST", body={
"amountCents": 1000,
"externalRef": "order-123",
"customer": {
"name": "Maria Silva",
"email": "maria@example.com",
"phone": "11999998888",
"document": {"number": "12345678901", "type": "cpf"},
},
})
if status >= 400:
raise INFIError(status, data.get("error"))
print(data["transactionId"], data["pixPayload"])
# Initiate withdrawal (mind 202).
# Currently only the registered account holder's CPF/CNPJ.
status, data = infi_request("/withdraw", method="POST", body={
"amountCents": 5000,
"pixKey": "12345678901",
"pixKeyType": "cpf",
})
if status == 202:
# failed_unknown — do not resend
pass
elif status >= 400:
raise INFIError(status, data.get("error"))Receive webhook (Flask)
import hmac, hashlib, os, time
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/webhooks/infi")
def infi_webhook():
ts = request.headers.get("X-Infi-Timestamp", "")
sig_header = request.headers.get("X-Infi-Signature", "")
sig = sig_header[7:] if sig_header.startswith("sha256=") else ""
try:
ts_num = int(ts)
except ValueError:
abort(401)
if abs(time.time() - ts_num) > 300:
abort(401)
raw = request.get_data()
payload = f"{ts}.".encode() + raw
expected = hmac.new(
os.environ["INFI_WEBHOOK_SECRET"].encode(),
payload,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected, sig):
abort(401)
event = request.get_json()
# Idempotency by (transactionId, status). Respond < 8s.
return "", 200