Skip to main content

daraja-mock

A small local test double for the Safaricom M-Pesa Daraja API, built on Flask. It lets you exercise OAuth and STK Push flows (and the request shapes of B2C v3, transaction status and account balance; there is no C2B, B2B or reversal endpoint, and those paths return 404) without a Safaricom account, credentials or internet access.

CI Python License

What this is, and is not. A test double, not a simulator of Safaricom's behaviour, and not affiliated with Safaricom. Only the STK Push query result is configurable. B2C, Account Balance and Transaction Status always return an "accepted" response, and no asynchronous result callbacks are sent. See Limits.

Install

pip install daraja-mock    # installs Flask

Quickstart

import requests
from daraja_mock import DarajaMock

mock = DarajaMock()
base_url = mock.run_thread(port=18080)      # non-blocking; returns "http://127.0.0.1:18080"

token = requests.get(f"{base_url}/oauth/v1/generate").json()["access_token"]
headers = {"Authorization": f"Bearer {token}"}

push = requests.post(
    f"{base_url}/mpesa/stkpush/v1/processrequest", headers=headers,
    json={"BusinessShortCode": "174379", "Amount": 100, "PhoneNumber": "254712345678",
          "CallBackURL": "https://example.com/callback", "AccountReference": "Order001", "TransactionDesc": "Payment"},
).json()
assert push["ResponseCode"] == "0"

mock.set_stk_result(1032)                   # STK queries now report "cancelled by user"
status = requests.post(f"{base_url}/mpesa/stkpushquery/v1/query", headers=headers,
                       json={"CheckoutRequestID": push["CheckoutRequestID"]}).json()
assert status["ResultCode"] == "1032"

Configuration

Method Effect
set_stk_result(code) The ResultCode returned by every STK Push query. Described codes: 0 success, 1 insufficient balance, 1001 and 2001 invalid initiator, 1032 cancelled by user, 1037 timeout. Any other code is returned as Error <code>.
reset() Restore defaults and clear the request log.
request_log() List of recorded requests, each a dict with method, path, body and ts.
set_b2c_result(...), set_balance(...) No effect yet (they warn). The B2C and balance endpoints always accept.

The STK query endpoint returns the configured ResultCode for any CheckoutRequestID; it does not look the id up, and it returns a fresh random CheckoutRequestID of its own.

Endpoints

Endpoint Method Behaviour
/oauth/v1/generate GET Returns access_token and expires_in; credentials are not checked.
/mpesa/stkpush/v1/processrequest POST Accepts the request; ResponseCode is "0".
/mpesa/stkpushquery/v1/query POST Returns the configured ResultCode.
/mpesa/b2c/v3/paymentrequest POST Always accepted.
/mpesa/transactionstatus/v1/query POST Always accepted.
/mpesa/accountbalance/v1/query POST Always accepted.
/mock/balance-callback POST Receives a balance result if you use it as your callback URL.
/health GET {"status": "ok", "version": ...}

Standalone server

python -m daraja_mock                 # http://127.0.0.1:8765
python -m daraja_mock --port 9000
daraja-mock --port 9000               # the same, as an installed command

Use with pesa-cli

pesa-cli 1.0.1 and later reads PESA_BASE_URL, so its commands can run against this server:

python -m daraja_mock --port 8765 &
export PESA_BASE_URL=http://127.0.0.1:8765
pesa auth && pesa stk push 0712345678 100

daraja-v3 (the mpesa-python SDK) 0.1.2 and later accept MpesaClient(..., base_url="http://localhost:8765"), so the SDK can be pointed at this server; its own test suite does exactly that. base_url must be https://, or http:// for localhost only.

Limits

  • Credentials, shortcodes, passkeys and callback URLs are not validated.
  • No asynchronous result or callback delivery: STK, B2C and balance results that real Daraja posts to your URLs are not sent.
  • STK query is stateless (see above). No C2B URL registration endpoint.
  • It runs on Flask's development server, in a daemon thread for run_thread, in one process.

Tests

pip install -e ".[dev]" && python -m pytest

The tests also fail if this README names a class, method or endpoint that does not exist, and they run the Quickstart above.

Part of the nairobi-stack East Africa engineering ecosystem. Maintained by Gabriel Mahia. Kenya × USA.

Metadata

Release files for daraja-mock 1.0.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for daraja-mock 1.0.6
File Size Uploaded Provenance Actions
daraja_mock-1.0.6.tar.gz 9.7 kB With provenance Details for daraja_mock-1.0.6.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for daraja-mock 1.0.6
File Interpreter ABI Platform Actions
daraja_mock-1.0.6-py3-none-any.whl Python 3 none any Details for daraja_mock-1.0.6-py3-none-any.whl

Total release size: 17.7 kB

Release files / daraja_mock-1.0.6.tar.gz

Download URL daraja_mock-1.0.6.tar.gz
Size 9.7 kB
Tags Source
SHA-256 checksum
How to use checksums
976cb26b35cf13fdd159703bd9aded104710fd418d839b1101f1cbb39414b531
BLAKE2b-256 checksum
How to use checksums
e0f220bd8c6b7a4b669cd9ffa49281faf3eaf62d42572a7ae49b1c81086bfab9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / daraja_mock-1.0.6-py3-none-any.whl

Download URL daraja_mock-1.0.6-py3-none-any.whl
Size 7.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
410dd7f5fbff6fdf5f05d04b1d7be5fbdfda77a7ede0dc00ca6e0ea2faee8ff8
BLAKE2b-256 checksum
How to use checksums
b393bc767f7627ec2c70342685d3617719b08a93f236b66f3fda94e342eccad3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Security for daraja-mock 1.0.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for daraja_mock-1.0.6.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page