Skip to main content

Official UQPAY Python SDK

Project description

UQPAY Python SDK

License: MIT

Official Python SDK for the UQPAY API — a comprehensive payment and card issuing platform.

Requirements

  • Python 3.9+

Installation

pip install uqpay

Quick Start

from uqpay import UQPayClient

# Sandbox (for testing)
client = UQPayClient(client_id="your-client-id", api_key="your-api-key", environment="sandbox")

# Production
client = UQPayClient(client_id="your-client-id", api_key="your-api-key", environment="production")

Authentication

The SDK handles OAuth2 authentication automatically. It fetches an access token using your client_id and api_key, caches it, and refreshes it before expiry. You do not need to manage tokens manually.

Configuration

client = UQPayClient(
    client_id="your-client-id",
    api_key="your-api-key",
    environment="sandbox",       # "sandbox" (default) or "production"
    timeout=30.0,                # request timeout in seconds
    max_retries=2,               # automatic retries on transient errors
    log_level="none",            # "none" | "error" | "warn" | "info" | "debug"
    redact_fields=["card_number", "cvc"],
)

Per-request options:

result = client.banking.payouts.create(
    {...},
    request_options={
        "idempotency_key": "unique-key",
        "on_behalf_of": "sub-account-id",
        "timeout": 60,
        "max_retries": 0,
    },
)

Environment Variables

UQPAY_CLIENT_ID=your-client-id
UQPAY_API_KEY=your-api-key

API Coverage

Banking API

Resource Operations
Balances List, Retrieve, ListTransactions
Transfers Create, List, Retrieve
Deposits List, Retrieve
Beneficiaries Create, List, Retrieve, Update, Delete, Check
Payouts Create, List, Retrieve
Virtual Accounts Create, List
Conversions CreateQuote, Create, List, Retrieve, ListDates, ListCurrentRates
Payment Methods List

Issuing API

Resource Operations
Cardholders Create, List, Retrieve, Update
Cards Create, List, Retrieve, Update, UpdateStatus, Recharge, Withdraw, RetrieveOrder, CreatePanToken, GetSecureIframeUrl
Transactions List, Retrieve
Products List
Balances List, Retrieve, ListTransactions
Transfers Create, Retrieve
Reports Create, Download
Auth Decision PGP-based real-time authorization

Connect API

Resource Operations
Accounts Create, List, Retrieve
Sub-Accounts Create
Additional Docs Get

Payment API

Resource Operations
Payment Intents Create, Confirm, Capture, Cancel, List, Retrieve, Update
Refunds Create, List, Retrieve
Bank Accounts Create, List, Retrieve, Update
Payouts Create, List, Retrieve
Balances List, Retrieve
Attempts List, Retrieve
Settlements List

Supporting API

Resource Operations
Files Upload, DownloadLinks

Simulator (sandbox only)

Resource Operations
Issuing Authorize, Reverse
Deposits Simulate

Resources

Banking

# Balances
balances = client.banking.balances.list({"page_number": 1, "page_size": 20})
balance = client.banking.balances.retrieve("SGD")
txns = client.banking.balances.list_transactions({"page_number": 1, "page_size": 20})

# Transfers
transfer = client.banking.transfers.create({
    "source_account_id": "acc-123",
    "target_account_id": "acc-456",
    "currency": "SGD",
    "amount": "100.00",
    "reason": "Fund sub-account",
})
transfers = client.banking.transfers.list({"page_number": 1, "page_size": 20})
transfer = client.banking.transfers.retrieve("transfer-id")

# Deposits
deposits = client.banking.deposits.list({"page_number": 1, "page_size": 20})
deposit = client.banking.deposits.retrieve("deposit-id")

# Beneficiaries
beneficiary = client.banking.beneficiaries.create({...})
beneficiaries = client.banking.beneficiaries.list({"page_number": 1, "page_size": 20})
beneficiary = client.banking.beneficiaries.retrieve("ben-id")
client.banking.beneficiaries.update("ben-id", {})
client.banking.beneficiaries.delete("ben-id")
client.banking.beneficiaries.check({...})

# Payouts
payout = client.banking.payouts.create({
    "beneficiary_id": "ben-123",
    "currency": "SGD",
    "amount": "50.00",
    "purpose_code": "PERSONAL",
})
payouts = client.banking.payouts.list({"page_number": 1, "page_size": 20})
payout = client.banking.payouts.retrieve("payout-id")

# Virtual Accounts
va = client.banking.virtual_accounts.create({"currency": "USD"})
vas = client.banking.virtual_accounts.list({"page_number": 1, "page_size": 20})

# Conversions
quote = client.banking.conversions.create_quote({
    "buy_currency": "SGD",
    "sell_currency": "USD",
    "buy_amount": "100.00",
    "conversion_date": "2026-04-15",
})
conversion = client.banking.conversions.create({...})
rates = client.banking.conversions.list_current_rates()
dates = client.banking.conversions.list_dates({"currency_from": "USD", "currency_to": "SGD"})

# Payment Methods
methods = client.banking.payment_methods.list({"country": "US", "currency": "USD"})

Issuing

Cardholders

cardholder = client.issuing.cardholders.create({
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "phone_number": "+6591234567",
    "country_code": "SG",
    "date_of_birth": "1990-01-15",
})
cardholders = client.issuing.cardholders.list({"page_number": 1, "page_size": 20})
cardholder = client.issuing.cardholders.retrieve("ch-id")
client.issuing.cardholders.update("ch-id", {"first_name": "Updated"})

Cards

card = client.issuing.cards.create({
    "cardholder_id": "ch-id",
    "product_id": "prod-id",
    "card_type": "VIRTUAL",
    "currency": "SGD",
})
cards = client.issuing.cards.list({"page_number": 1, "page_size": 20})
card = client.issuing.cards.retrieve("card-id")
client.issuing.cards.update("card-id", {"metadata": {"order_id": "ord-001"}})
client.issuing.cards.update_status("card-id", {"status": "FROZEN"})

# Recharge and withdraw
client.issuing.cards.recharge("card-id", {"amount": "100.00", "currency": "SGD"})
client.issuing.cards.withdraw("card-id", {"amount": "50.00", "currency": "SGD"})

# Secure card info
result = client.issuing.cards.create_pan_token("card-id")
result = client.issuing.cards.get_secure_iframe_url("card-id")

# Card orders
order = client.issuing.cards.retrieve_order("card-order-id")

Transactions, Products, Balances, Transfers

# Transactions
txns = client.issuing.transactions.list({"page_number": 1, "page_size": 20})
txn = client.issuing.transactions.retrieve("txn-id")

# Products
products = client.issuing.products.list({"page_number": 1, "page_size": 20})

# Issuing balances
balances = client.issuing.balances.list({"page_number": 1, "page_size": 20})
balance = client.issuing.balances.retrieve("SGD")
client.issuing.balances.list_transactions({"page_number": 1, "page_size": 20})

# Issuing transfers
transfer = client.issuing.transfers.create({
    "source_account_id": "master-acc-id",
    "destination_account_id": "sub-acc-id",
    "currency": "SGD",
    "amount": 100,
})
transfer = client.issuing.transfers.retrieve("transfer-id")

# Reports
report = client.issuing.reports.create({
    "report_type": "SETTLEMENT",
    "start_time": "2026-01-01T00:00:00Z",
    "end_time": "2026-04-10T23:59:59Z",
})
csv_data = client.issuing.reports.download(report["report_id"])

Connect

# Accounts
accounts = client.connect.accounts.list({"page_number": 1, "page_size": 20})
account = client.connect.accounts.retrieve("acc-id")
account = client.connect.accounts.create({...})

# Sub-accounts
sub_account = client.connect.sub_accounts.create({...})

# Additional documents
docs = client.connect.additional_docs.get()

Payment

# Payment Intents
intent = client.payment.payment_intents.create({
    "amount": "100.00",
    "currency": "SGD",
    "merchant_order_id": "order-001",
    "return_url": "https://example.com/return",
})
client.payment.payment_intents.confirm(intent["payment_intent_id"], {"payment_method": {...}})
client.payment.payment_intents.capture("pi-id")
client.payment.payment_intents.cancel("pi-id", {"cancellation_reason": "requested_by_customer"})
intents = client.payment.payment_intents.list({"page_number": 1, "page_size": 20})

# Refunds
refund = client.payment.refunds.create({
    "payment_intent_id": "pi-id",
    "amount": "50.00",
    "reason": "requested_by_customer",
})
refunds = client.payment.refunds.list({"page_number": 1, "page_size": 20})
refund = client.payment.refunds.retrieve("refund-id")

# Bank Accounts
bank_account = client.payment.bank_accounts.create({...})
bank_accounts = client.payment.bank_accounts.list({"page_number": 1, "page_size": 20})

# Payouts
payout = client.payment.payouts.create({...})
payouts = client.payment.payouts.list({"page_number": 1, "page_size": 20})

# Balances and Attempts
balances = client.payment.balances.list({"page_number": 1, "page_size": 20})
balance = client.payment.balances.retrieve("SGD")
attempts = client.payment.attempts.list({"page_number": 1, "page_size": 20})
attempt = client.payment.attempts.retrieve("attempt-id")

# Settlements
settlements = client.payment.settlements.list({"page_number": 1, "page_size": 20})

Supporting (File Upload / Download)

with open("document.pdf", "rb") as f:
    result = client.supporting.files.upload(
        file_data=f.read(),
        filename="document.pdf",
        mime_type="application/pdf",
    )

links = client.supporting.files.download_links([result["file_id"]])

Simulator (sandbox only)

The simulator is only available in the sandbox environment and raises SimulatorNotAvailableError in production.

# Simulate a card authorization
result = client.simulator.issuing.authorize({
    "card_id": "card-id",
    "amount": 25.0,
    "currency": "SGD",
    "transaction_status": "APPROVED",
})

# Simulate a reversal
client.simulator.issuing.reverse({
    "card_id": "card-id",
    "transaction_id": result["transaction_id"],
})

# Simulate a deposit
client.simulator.deposits.simulate({
    "currency": "SGD",
    "amount": 500.0,
})

Pagination

All list methods accept page_number and page_size:

page = 1
while True:
    result = client.issuing.cards.list({"page_number": page, "page_size": 50})
    items = result.get("items") or result.get("list") or []
    if not items:
        break
    for card in items:
        print(card["card_id"])
    page += 1

Webhooks

client = UQPayClient(
    client_id="your-client-id",
    api_key="your-api-key",
    webhook_secret="your-webhook-secret",
)

# In your HTTP handler:
from uqpay import UQPayWebhookError

try:
    event = client.webhooks.construct_event(
        raw_body=request.get_data(),
        headers=dict(request.headers),
    )
    print(event["event_type"], event["data"])
except UQPayWebhookError as e:
    return str(e), 400

The verifier checks the HMAC-SHA256 signature and rejects requests with a timestamp older than 300 seconds.

Authorization Decision (PGP)

Handle real-time card authorization decisions. UQPAY sends PGP-encrypted transactions to your endpoint; the SDK decrypts them, calls your handler, and returns an encrypted response.

from uqpay.crypto import generate_auth_decision_key_pair

# Generate a key pair once and store securely
keys = generate_auth_decision_key_pair(name="MyApp", email="ops@example.com")

# Configure at startup
client.issuing.auth_decision.configure(
    private_key=keys["private_key"],
    uqpay_public_key="<UQPAY public key from dashboard>",
)

# Define your decision function
def decide(transaction: dict) -> dict:
    if transaction.get("amount", 0) > 10000:
        return {"response_code": "05"}  # Decline
    return {"response_code": "00", "partner_reference_id": "ref-001"}

# In your HTTP handler:
encrypted_response = client.issuing.auth_decision.handle(
    body=request.get_data(),
    headers=dict(request.headers),
    decide=decide,
)

Error Handling

from uqpay import (
    UQPayError,
    AuthenticationError,
    ForbiddenError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    ServerError,
)

try:
    balance = client.banking.balances.retrieve("SGD")
except AuthenticationError as e:
    print(f"Authentication failed: {e.message}")
except ForbiddenError as e:
    print(f"Access denied: {e.message}")
except NotFoundError as e:
    print(f"Not found: {e.message}")
except ValidationError as e:
    print(f"Validation error [{e.code}]: {e.message}")
except RateLimitError as e:
    print(f"Rate limited (HTTP {e.http_status})")
except ServerError as e:
    print(f"Server error: {e.message}")
except UQPayError as e:
    print(f"{e.type}: {e.message} (HTTP {e.http_status})")

All errors expose: message, code, type, http_status, idempotency_key.

Testing

pip install -e ".[dev]"
cp .env.example .env  # fill in sandbox credentials
pytest tests/ -v

# Skip integration tests
SKIP_INTEGRATION_TESTS=true pytest tests/ -v

Documentation

License

This project is licensed under the MIT License — see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uqpay-0.1.0.tar.gz (34.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

uqpay-0.1.0-py3-none-any.whl (61.3 kB view details)

Uploaded Python 3

File details

Details for the file uqpay-0.1.0.tar.gz.

File metadata

  • Download URL: uqpay-0.1.0.tar.gz
  • Upload date:
  • Size: 34.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for uqpay-0.1.0.tar.gz
Algorithm Hash digest
SHA256 511b136a88bbc30c27382764f32efb5996c4b2447f2682eea04682c6b5103afc
MD5 d1e9703c93a7af5f98c9bd4eb67f14fd
BLAKE2b-256 cf87076ad88cab4e58985cd01ca859f18849889dc752879bd6f514faf408cec1

See more details on using hashes here.

File details

Details for the file uqpay-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: uqpay-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 61.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for uqpay-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 153c31bf6ba979bd937473f8c703ab0040a304ca71a1d09fd18e6342f7e72410
MD5 c35e57ca2f87a772641720e1e7d4f7de
BLAKE2b-256 455c34e593680c12e3a5f2569f7fb6e204c8cd84f3ce29e12a0058bd6c7f814a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page