Changelog
View SourceAll notable changes to this project are documented here. This project adheres to Semantic Versioning.
v0.2.0
A substantial release. 0.1.0 code keeps working — every old function remains as a deprecated shim, returning the shapes it always did, until 0.3.0.
Security
- TLS certificate verification is now on. 0.1.0 passed
hackney: [:insecure]on every request, so the RSA-encrypted API key and the bearer session token travelled over connections that were never authenticated. Certificates and hostnames are now verified against the system trust store, and a regression test proves a known-bad certificate is rejected. - Request timeouts reduced from 500 seconds to 10s connect / 30s receive. The old value meant a hung endpoint blocked the caller for over eight minutes.
- The library's own
config/config.exsno longer carries credential-shaped placeholders, and CI fails the build if anything resembling a real API key reaches the package.
Fixed
- HTTP 403, 404, 429, 502 and 504 raised
FunctionClauseErrorinstead of returning an error tuple. Only ten statuses were handled; everything else crashed the caller. All statuses are handled now. - A non-JSON response body raised. Gateway HTML error pages and empty bodies now
return
{:error, %ElixirMpesa.Error{reason: :invalid_json}}. Base.decode64/1's bare:errorescaped through the encryption path and caused aWithClauseErrorfurther up. Malformed public keys now return a proper error, and whitespace in a key is tolerated.- The
direct_*helpers encrypted the wrong value — they calledencrypt_api_key/1whereencrypt_session_key/2was meant, silently discarding the session ID if any option was passed. input_currencyandinput_countrywere documented but read by nothing. They are now:currencyand:country, are actually applied, and are set together by:market.- Missing configuration produced
nil, which became a request tohttps://openapi.m-pesa.com//ipg/v2//getSession/. Configuration is now validated up front with an error naming the missing key. mix compile --warnings-as-errorsandmix format --check-formattedboth failed on 0.1.0. Both pass.
Added
- Automatic session management.
ElixirMpesa.Sessionobtains a session key on first use, caches it per market, refreshes at 80% of its one-hour lifetime, collapses concurrent cache misses into a singlegetSessioncall, and re-authenticates once if M-Pesa rejects the key mid-flight. ElixirMpesa.Error, a single exception struct for every failure, with a documented atomreasonand acategory(:config,:crypto,:transport,:http,:api) that distinguishes "M-Pesa declined" from "the outcome is unknown".ElixirMpesa.Response, replacing raw string-keyed maps.Market presets —
market: :tanzania | :lesotho | :ghana | :drcsets the URL context, country and currency together.reversal/2is now reachable. It existed in 0.1.0 but was never exposed on the top-level module and was absent from the documentation.!variants for every operation, raising on failure.conversation_id/0for generating idempotency keys.@specand@typeon every public function — 0.1.0 had none at all — verified by dialyzer.- Eight guides, a real test suite (91 tests, 18 doctests, no network), credo, dialyzer and a CI workflow that matches this project.
llms.txtandAGENTS.mdfor coding assistants.
Changed
- HTTPoison replaced with Req, which verifies TLS by default
and makes the whole suite testable via
Req.Testwith no network. - A payment must now carry
"input_ThirdPartyConversationID". The library will not generate one for a payment: a generated ID would give each retry a fresh idempotency key and defeat M-Pesa's duplicate detection. Read-only queries still get one generated. - Payments are never retried automatically. Read-only queries are.
"input_Country","input_Currency"and"input_ServiceProviderCode"are filled in from configuration when omitted.- Minimum Elixir raised to 1.15, from a claimed 1.14 that was never tested and that Req does not support.
- Source files moved from
lib/ex_mpesa/tolib/elixir_mpesa/, matching the module names since the 0.1.0 rename. - Corrected the repository URL in the package metadata. It pointed at a GitHub user that does not exist, so the "GitHub" link on Hex and every "Source" link in the published docs were dead.
Deprecated
Removal in 0.3.0. See the upgrade guide.
c2b_single_stage,b2c_single_stage,b2b_single_stage→c2b/2,b2c/2,b2b/2direct_c2b_single_stage,direct_b2c_single_stage,direct_query_transaction_status→ the plain function of the same operation- Passing a session key to
query_transaction_status,query_beneficiary_name,query_direct_debit,direct_debit_creation,direct_debit_paymentanddirect_debit_cancel→ pass options instead ElixirMpesa.GenerateSessionKeyandencrypt_api_key/1,generate_session_key/2,encrypt_session_key/2→ handled automatically;ElixirMpesa.session_key/1if neededElixirMpesa.HttpRequest→ removed, replaced byElixirMpesa.Client
v0.1.0
Initial release. Session key generation, C2B, B2C, B2B, transaction status queries, direct debit operations and beneficiary name queries.