Client for the DurraPay Platform API. Python 3.8+.
pip install durrapayimport os
from durrapay import DurraPay
dp = DurraPay(api_key=os.environ["DURRAPAY_KEY"]) # dpk_test_... or dpk_live_...
# Who am I?
print(dp.me())
# Collect in Kenya (M-Pesa STK).
# merchant_reference is YOUR key — echoed back on the webhook + status so you can
# reconcile. metadata is optional JSON returned verbatim.
c = dp.collections.stk(
phone="254705423996",
amount_minor=150000, # KES 1,500.00 (minor units)
currency="KES",
reference="vincent-anjiri-1001",
merchant_reference="vincent-anjiri:44718",
metadata={"order_id": "1001"},
)
# The response is "queued", NOT paid. Act on the payment.completed/.failed
# webhook — poll status only as a fallback.
dp.collections.get(c["payment_id"])
# Send cross-border (FX + payout). dest_type: PHONE | PAYBILL | TILL | BANK
q = dp.transfers.quote(from_currency="KES", destination_country="TZ", from_amount_minor=1_000_000)
dp.transfers.create(
quote_id=q["quote_id"], dest_type="PHONE", dest_phone="254705423996",
dest_name="Vincent Anjiri", merchant_reference="vincent-anjiri:payout:44718",
)
# Customers, recipients, payment links, balances, usage…
dp.customers.create(name="Vincent Anjiri", email="vincent@example.com")
dp.balances()Idempotency keys are auto-generated for POSTs (override with idempotency_key=).
Errors raise DurraPayError with .status, .code, and .body.
Async by design: collections and payouts finish via webhook, not the API response. See the transaction lifecycle.