Dynamic QR Code
Dynamic QR Codes can only be scanned and completed from inside the M-Pesa mobile application. They are not usable from generic QR readers.
Generate and manage dynamic M-Pesa QR codes for payments and transfers. Dynamic QR lets you create a QR payload for a single transaction that includes amount, reference and recipient details.
User Stories
- As a fintech product owner, I want to programmatically generate dynamic QR codes so that customers can easily make payments.
- As an integrations developer, I want a simple client and clear webhook callbacks so I can implement reliable end-to-end flows with minimal boilerplate.
- As a billing operations engineer, I want result and timeout notifications with acknowledgements so I can reconcile transactions and trigger retries or alerts when needed.
- As a reseller partner, I want a tested SDK and examples so I can onboard quickly and reduce integration defects.
Parameters
| Parameter | Type | Description |
|---|---|---|
MerchantNamerequired str | String | Merchant or business name shown on the QR experience (e.g., store name). |
RefNorequired str | String | Transaction reference or account identifier (e.g., invoice or order id). |
Amountrequired int | Integer | Amount in KES. Must be greater than zero. |
TrxCoderequired str | String | Transaction type code. Supported values: BG, WA, PB, SM, SB. |
CPIrequired str | String | Credit Party Identifier: mobile number, paybill, till or business identifier depending on TrxCode. |
Sizerequired str | String | QR image size in pixels (square). Example: '300'. |
Integration Overview
Two integration patterns: use the library-level client (recommended) for quick setup or the lower-level service for custom workflows. Both are available as sync and async variants.
QR generation is a single request/response call with no result or timeout callback — there's no webhook step to reason about here, unlike STK Push or B2C. The only choice is whether you want client.dynamic_qr.generate(...) to block or to await. Reach for AsyncMpesaClient if you're generating QR codes from an async def route handler (e.g. an endpoint that returns a QR image per checkout session), or generating several QR codes for a batch of orders concurrently.
Use the high-level client to handle authentication and common defaults. It gives a simple surface for generating dynamic QR codes.
Quick Start (Sync)
# Example: using MpesaClient facade to create a dynamic QRfrom mpesakit import MpesaClientfrom mpesakit.dynamic_qr_code import DynamicQRTransactionType
client = MpesaClient( consumer_key="YOUR_KEY", consumer_secret="YOUR_SECRET", environment="sandbox",)
response = client.dynamic_qr.generate( merchant_name="Corner Store", ref_no="ORDER-1001", amount=250, trx_code=DynamicQRTransactionType.BUY_GOODS, cpi="373132", size="300",)
if response.is_successful: print("QR generated", response.QRCode)else: print("Failed:", response.ResponseDescription)- Provide either numeric/traditional values for TrxCode (use the transaction type enum) and ensure CPI matches the TrxCode semantics (mobile vs business).
- Amount must be > 0.
Quick Start (Async)
import asynciofrom mpesakit import AsyncMpesaClientfrom mpesakit.dynamic_qr_code import DynamicQRTransactionType
async def main(): async with AsyncMpesaClient( consumer_key="YOUR_KEY", consumer_secret="YOUR_SECRET", environment="sandbox", ) as client: response = await client.dynamic_qr.generate( merchant_name="Corner Store", ref_no="ORDER-1001", amount=250, trx_code=DynamicQRTransactionType.BUY_GOODS, cpi="373132", size="300", )
if response.is_successful: print("QR generated", response.QRCode) else: print("Failed:", response.ResponseDescription)
asyncio.run(main())If you need to produce QR codes for many orders at once (e.g. a bulk invoice run), gather the coroutines rather than awaiting each one sequentially:
orders = [
dict(ref_no="ORDER-1001", amount=250),
dict(ref_no="ORDER-1002", amount=1200),
# ...
]
responses = await asyncio.gather(*(
client.dynamic_qr.generate(
merchant_name="Corner Store",
ref_no=o["ref_no"],
amount=o["amount"],
trx_code=DynamicQRTransactionType.BUY_GOODS,
cpi="373132",
size="300",
)
for o in orders
))
In a long-lived service (e.g. AsyncMpesaClient wired up as a FastAPI dependency), construct it once at startup and call await client.aclose() on shutdown instead of opening a new async with block per request.
Response
- Response objects are typed models with attributes matching the API response fields, whether returned directly (sync) or via
await(async). - Use
is_successfulto check if the request succeeded. - If you need the raw response data, use
model_dump(mode="json")to get a dictionary representation.
Response Schema
DynamicQRGenerateResponse — returned by client.dynamic_qr.generate(...). This is a synchronous, single-call API with no result/timeout callbacks.
| Parameter | Type | Description |
|---|---|---|
ResponseCoderequired str | int | String/Integer | '00' indicates the QR code was generated successfully. |
ResponseDescriptionrequired str | String | Human readable status description, e.g. 'QR Code Successfully Generated.' |
QRCoderequired str | String | Base64-encoded QR code image data. |
{ "ResponseCode": "00", "ResponseDescription": "QR Code generated successfully", "QRCode": "iVBORw0KGgoAAAANSUhEUgAA..."}# Check success and extract QR payloadif response.is_successful: payload = response.QRCode # store or render payload as neededelse: print("Failed to generate QR:", response.ResponseDescription)- Validation errors (invalid TrxCode, bad CPI for SEND_MONEY, etc.) raise exceptions at request model creation time — before any network call, so this behaves identically for
client.dynamic_qr.generate(...)andawait client.dynamic_qr.generate(...). - HTTP or API-level errors should be caught and inspected (use the library exceptions to get code, message and HTTP status). Wrap the sync call in try/except, or the awaited call the same way.
Next Steps
- Implement a flow to render or serve the QR image to customers after generation.
- Monitor flow completion via M-Pesa app actions and reconcile transactions using your normal payment notifications and webhooks (see the STK Push and C2B guides for callback handling patterns).