Skip to main content

Python client for the Airtel Money Uganda Open APIs (Collections, Disbursements, KYC, Account) with built-in request signing and PIN encryption.

Project description

airtelmoney-ug

Python client for the Airtel Money Uganda Open APIs — Collections, Disbursements, KYC and Account — with built-in request signing (x-signature / x-key) and PIN encryption, automatic OAuth2 token management and friendly error-code lookups.

Features

  • OAuth2 client-credentials token handling with caching/auto-refresh.
  • Automatic message signing for write APIs (AES-256-CBC payload + RSA-encrypted key/IV).
  • Automatic RSA PIN encryption for disbursements.
  • Encryption-key fetching and caching.
  • Typed exceptions and a complete map of documented response_code values.
  • Fully covered by offline unit tests.

Installation

pip install airtelmoney-ug

For local development:

pip install -e ".[dev]"

Quick start

from airtelmoney import AirtelMoney

client = AirtelMoney(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
    environment="staging",   # or "production"
)

# Or load credentials from a JSON file (airtel_client_id / airtel_client_secret):
client = AirtelMoney.from_credentials_file("airtel_credentials.json")

# Or load from environment variables / a .env file (recommended):
client = AirtelMoney.from_env()

Default base URLs are https://openapiuat.airtel.africa (staging) and https://openapi.airtel.africa (production). Pass base_url=... to override, e.g. for the Uganda-specific endpoints in airtel_credentials.json.

Configuration via .env

Install the optional dependency and copy .env.example to .env:

pip install "airtelmoney-py[env]"
cp .env.example .env
Variable Description Default
AIRTEL_CLIENT_ID Application client id (required)
AIRTEL_CLIENT_SECRET Application client secret (required)
AIRTEL_ENVIRONMENT staging or production staging
AIRTEL_BASE_URL Explicit base URL (overrides environment)
AIRTEL_COUNTRY X-Country header UG
AIRTEL_CURRENCY X-Currency header UGX
from airtelmoney import AirtelMoney

client = AirtelMoney.from_env()  # reads .env if python-dotenv is installed

Usage

Collections

# USSD push payment (payload signed automatically using the consumer RSA key)
res = client.collection.payment(
    reference="Order #123",
    msisdn="752604392",
    amount=1000,
)
txn_id = res["data"]["transaction"]["id"]

# Transaction enquiry
client.collection.enquiry(txn_id)

# Refund a successful transaction
client.collection.refund("CI210104.1105.C00018")

Disbursements

# PIN is RSA-encrypted with the consumer public key automatically
res = client.disbursement.payment(
    msisdn="752604392",
    amount=500,
    reference="payout-1",
    pin="1234",
)
client.disbursement.enquiry(res["data"]["transaction"]["id"])

# Already have an encrypted PIN? Pass it directly:
client.disbursement.payment(
    msisdn="752604392", amount=500, reference="p-2",
    encrypted_pin="KYJExln8rZwb14G1K5UE5YF/lD7KheNUM171MUEG3/f/QD8nmNKRsa44",
)

KYC and Account

client.kyc.user_enquiry("256752604392")
client.account.balance()

Callbacks

Airtel posts transaction updates to your configured callback URL. For authenticated callbacks you can verify the signature:

# payload is the decoded JSON body Airtel POSTed to your callback URL
valid = client.collection.verify_callback_hash(payload, secret="YOUR_CLIENT_SECRET")

Manual signing / encryption

The signing primitives are exposed if you need them directly:

from airtelmoney import sign_payload, encrypt_pin

public_key = client.get_encryption_key()  # base64 DER RSA public key

signed = sign_payload(public_key, {"reference": "1234", "transaction": {"id": "x"}})
# signed.payload      -> exact JSON body you MUST send
# signed.x_signature  -> x-signature header
# signed.x_key        -> x-key header

enc_pin = encrypt_pin(public_key, "1234")

How signing works

  1. Generate a random 256-bit AES key and 128-bit IV.
  2. Base64-encode the key and IV.
  3. Fetch the consumer RSA public key (client.get_encryption_key()).
  4. Encrypt the JSON payload with AES/CBC/PKCS5Paddingx-signature header.
  5. Concatenate key:iv (both base64) and RSA-encrypt with the public key → x-key header.

The server decrypts key:iv with its private RSA key, re-encrypts the received payload and compares it against x-signature. A mismatch yields a Forbidden (DP00800001026 / DP00900001016).

Error handling

from airtelmoney import AirtelAPIError, describe, is_success

try:
    res = client.account.balance()
except AirtelAPIError as exc:
    print(exc.status_code, exc.response_code, exc.message)

# Interpret any documented response code
info = describe("DP00800001007")   # ResponseCode(code=..., reason='Not enough balance', ...)
is_success("DP00800001001")        # True

Response codes

All documented codes are available via airtelmoney.RESPONSE_CODES and describe(), covering encryption, collection (DP008...), disbursement (DP009...), user enquiry (DP022...) and balance (DP021...).

Testing

pip install -e ".[dev]"
pytest

License

MIT

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

airtelmoney_py-1.0.1.tar.gz (20.3 kB view details)

Uploaded Source

Built Distribution

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

airtelmoney_py-1.0.1-py3-none-any.whl (19.3 kB view details)

Uploaded Python 3

File details

Details for the file airtelmoney_py-1.0.1.tar.gz.

File metadata

  • Download URL: airtelmoney_py-1.0.1.tar.gz
  • Upload date:
  • Size: 20.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for airtelmoney_py-1.0.1.tar.gz
Algorithm Hash digest
SHA256 85ab6d8e18d766813747c8c73a53a078e96615abdc531b62bb7800e9e8179edb
MD5 402e14f58f178bbbf7d97765a8b11aed
BLAKE2b-256 4195ea869951e169f6f597286afaf5f84c7c49f5fea9409860b55ba9b3134a81

See more details on using hashes here.

Provenance

The following attestation bundles were made for airtelmoney_py-1.0.1.tar.gz:

Publisher: publish.yml on robin-001/airtelmoney-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file airtelmoney_py-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: airtelmoney_py-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 19.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for airtelmoney_py-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2e6bd9c35f19cb4c328a5c4873df1061927cf79ef96f55be52f520f3c9313245
MD5 9a0b6ac9996d8cca29bfac18aaa66af8
BLAKE2b-256 bfb231ef1ce7adabb1c7d6f8e4b584ec649f3f631ba4565cfd9b1d9ab2e64576

See more details on using hashes here.

Provenance

The following attestation bundles were made for airtelmoney_py-1.0.1-py3-none-any.whl:

Publisher: publish.yml on robin-001/airtelmoney-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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