"""Noryk Gateway: exemplo Python 3 no backend, usando somente a biblioteca padrão.""" import json import os import re import sys from urllib.error import HTTPError, URLError from urllib.parse import urlparse from urllib.request import Request, HTTPRedirectHandler, build_opener class NoRedirect(HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): return None api_key = os.environ.get("NORYK_API_KEY") operation_key = os.environ.get("IDEMPOTENCY_KEY") base = os.environ.get("NORYK_BASE_URL", "https://gateway.noryk.finance").rstrip("/") parsed = urlparse(base) if not api_key or not operation_key: raise SystemExit("Configure NORYK_API_KEY e a IDEMPOTENCY_KEY já persistida para este pedido.") if re.search(r"[\x00-\x20\x7f]", api_key): raise SystemExit("A credencial não pode conter espaços ou caracteres de controle.") if not re.fullmatch(r"[a-zA-Z0-9_.:-]{8,128}", operation_key): raise SystemExit("IDEMPOTENCY_KEY deve ter de 8 a 128 caracteres permitidos.") if parsed.username or parsed.password or parsed.query or parsed.fragment or parsed.path: raise SystemExit("NORYK_BASE_URL deve conter apenas a origem da API.") if parsed.scheme != "https" and not (parsed.scheme == "http" and parsed.hostname in {"localhost", "127.0.0.1", "::1"}): raise SystemExit("Use HTTPS; HTTP é permitido somente no desenvolvimento local.") payload = json.dumps({"amountCents": 10000, "description": "Pedido 000001"}).encode("utf-8") request = Request(base + "/v1/charges", data=payload, method="POST", headers={ "Authorization": "Bearer " + api_key, "Content-Type": "application/json", "Idempotency-Key": operation_key, }) try: # Sem reenvio automático nem redirecionamento de credenciais. with build_opener(NoRedirect()).open(request, timeout=15) as response: result = json.load(response) if not isinstance(result, dict) or not isinstance(result.get("id"), str) or not result["id"].strip() or not isinstance(result.get("status"), str) or not result["status"] or type(result.get("amountCents")) is not int or result["amountCents"] != 10000: raise ValueError("Incomplete confirmation") # Persista result["id"] junto da chave do pedido no seu banco. # result["qrCode"] é o Pix copia e cola; não tem valor financeiro no sandbox. print(json.dumps({key: result.get(key) for key in ("id", "status", "amountCents", "feeCents", "netCents")})) except HTTPError as error: try: body = json.load(error) except (ValueError, OSError): body = {} detail = body.get("error", {}) if isinstance(body, dict) else {} if not isinstance(detail, dict): detail = {} print(json.dumps({"httpStatus": error.code, "code": detail.get("code", "HTTP_ERROR"), "requestId": detail.get("requestId") or error.headers.get("x-request-id")}), file=sys.stderr) raise SystemExit(1) except (URLError, TimeoutError, ValueError): raise SystemExit("Resultado sem confirmação. Preserve o mesmo corpo e a chave persistida; consulte a operação antes de tentar novamente.")