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.0.tar.gz (19.7 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.0-py3-none-any.whl (19.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: airtelmoney_py-1.0.0.tar.gz
  • Upload date:
  • Size: 19.7 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.0.tar.gz
Algorithm Hash digest
SHA256 095e5d800204076e5429131efea17b642ff9bb20ade5d014bcdda23333e82d80
MD5 1b102b10d5a397d8db496c157b9e1087
BLAKE2b-256 cf262b3b6e13d1b99d3a88d159ca569e5e24f3c5eed0b0b8f97b4dd00f78a477

See more details on using hashes here.

Provenance

The following attestation bundles were made for airtelmoney_py-1.0.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: airtelmoney_py-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 19.0 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 afee87ae9aeb3aa7ab7bf7f59e81b4a2c8595de9c1a12b310471c3a5479422d9
MD5 1c97f9b1f4e0e73b93249153091a7641
BLAKE2b-256 193b99dafe416abfd76e0f288a6d35fdf3a91ec24c78def707b632365b05963a

See more details on using hashes here.

Provenance

The following attestation bundles were made for airtelmoney_py-1.0.0-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