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.ug (staging) and https://openapi.airtel.ug (production). Pass base_url=... to override, e.g. for the pan-African endpoints https://openapi.airtel.africa.

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.5.tar.gz (20.5 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.5-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: airtelmoney_py-1.0.5.tar.gz
  • Upload date:
  • Size: 20.5 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.5.tar.gz
Algorithm Hash digest
SHA256 4369e6aaf9047b3b9da13eb7f9e29cabbca2b17d025d210c07b9376c21f2739b
MD5 78a43adc1be9092dd8170cf9135fb97f
BLAKE2b-256 ceb54e9984120887019027ad44a96fbdf98df3d3eb58339e3e1359ad7b282be8

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: airtelmoney_py-1.0.5-py3-none-any.whl
  • Upload date:
  • Size: 19.4 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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 49e64f0b7149546a266ca95ee54b57f8d44c4d460016626195f4d42d50bf5281
MD5 219dd11a7d59fb84c1e56ba5c90cfd3a
BLAKE2b-256 ad47911d4260ddbb0095a9519b7e7eb974139ca7085dca4f7fbef294a4080d48

See more details on using hashes here.

Provenance

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