"""Python 3. Run with NUEPAY_TEST_KEY set. Test keys only; no third-party packages.""" import json import os import re import uuid import urllib.request import urllib.error key = os.environ.get("NUEPAY_TEST_KEY", "") base = os.environ.get("NUEPAY_BASE_URL", "https://api.nuepay.net/v1").rstrip("/") if not re.fullmatch(r"np_test_[a-f0-9]{48}", key): raise RuntimeError("Set NUEPAY_TEST_KEY to your sandbox key.") class NoRedirect(urllib.request.HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): return None def nuepay(method, path, body=None, idempotency=None): headers = {"Authorization": "Bearer " + key, "Accept": "application/json", "Content-Type": "application/json"} if idempotency: headers["Idempotency-Key"] = idempotency request = urllib.request.Request(base + path, data=json.dumps(body).encode() if body is not None else None, headers=headers, method=method) try: with urllib.request.build_opener(NoRedirect).open(request, timeout=30) as response: return json.load(response)["data"] except urllib.error.HTTPError as error: detail = json.load(error) raise RuntimeError(f"{detail.get('code')}: {detail.get('message')} Request ID: {detail.get('request_id')}") from None # Persist with the order before sending; keep the same UUID for retries after connection errors. idempotency = str(uuid.uuid4()) payment = nuepay("POST", "/collections", {"amount": "500.00", "currency": "UGX", "phone": "0772000000", "merchant_reference": "example-order"}, idempotency) result = nuepay("POST", "/sandbox/transactions/" + payment["reference"] + "/simulate", {"outcome": "success"}) print(json.dumps(result, indent=2))