Upgrading
View Source0.1.0 → 0.2.0
Your existing code keeps working. Every 0.1.0 function is still present, still returns
the same shapes, and is marked @deprecated so the compiler points you at its
replacement. The shims will be removed in 0.3.0.
Upgrade first, for the security fix
Version 0.1.0 sent every request with hackney: [:insecure], disabling TLS certificate
verification. The encrypted API key and bearer session token travelled over connections
that were never authenticated. 0.2.0 verifies certificates and hostnames on every call.
0.1.0 also raised FunctionClauseError instead of returning an error tuple on HTTP 403,
404, 429, 502 and 504, and on any non-JSON response body.
What changed
| 0.1.0 | 0.2.0 |
|---|---|
Manual encrypt → getSession → encrypt before every call | Automatic, cached, refreshed |
| Session key passed to every function | Not passed at all |
{:ok, %{"output_..." => ...}} | {:ok, %ElixirMpesa.Response{}} |
{:error, %{"output_..." => ...}} | {:error, %ElixirMpesa.Error{}} |
c2b_single_stage/3, direct_c2b_single_stage/2 | c2b/2 |
| Country and currency on every call | From configuration |
reversal unreachable from the top-level module | ElixirMpesa.reversal/2 |
| HTTPoison, TLS verification off | Req, TLS verified |
Before
{:ok, encrypted_api_key} = ElixirMpesa.encrypt_api_key()
{:ok, session_data} = ElixirMpesa.generate_session_key(encrypted_api_key)
{:ok, session_key} = ElixirMpesa.encrypt_session_key(session_data["output_SessionID"])
{:ok, result} = ElixirMpesa.c2b_single_stage(%{
"input_Amount" => 10.0,
"input_Country" => "LES",
"input_Currency" => "LSL",
"input_CustomerMSISDN" => "26675000000",
"input_ServiceProviderCode" => "00000",
"input_ThirdPartyConversationID" => "asv02e5958774f7ba228d83d0d689761",
"input_TransactionReference" => "T12344C",
"input_PurchasedItemsDesc" => "Test purchase"
}, session_key)
result["output_TransactionID"]After
{:ok, response} = ElixirMpesa.c2b(%{
"input_Amount" => "10",
"input_CustomerMSISDN" => "26675000000",
"input_ThirdPartyConversationID" => ElixirMpesa.conversation_id(),
"input_TransactionReference" => "T12344C",
"input_PurchasedItemsDesc" => "Test purchase"
})
response.transaction_idConfiguration changes
config :elixir_mpesa,
api_type: "sandbox",
- input_currency: "LSL",
- input_country: "LES",
- url_context: "vodacomLES",
+ market: :lesotho,
+ service_provider_code: "00000",
api_key: ...,
public_key: ...input_currency and input_country were documented in 0.1.0 but read by nothing —
you had to pass "input_Currency" and "input_Country" on every call regardless. They
are now :currency and :country, they are actually used, and :market sets all three
of them together.
url_context, country and currency still work individually if you prefer them.
Function renames
| 0.1.0 | 0.2.0 |
|---|---|
c2b_single_stage/2,3 · direct_c2b_single_stage/1,2 | c2b/1,2 |
b2c_single_stage/2,3 · direct_b2c_single_stage/1,2 | b2c/1,2 |
b2b_single_stage/2,3 | b2b/1,2 |
query_transaction_status/2,3 · direct_query_transaction_status/1,2 | query_transaction_status/1,2 |
direct_debit_creation/2,3 | direct_debit_creation/1,2 |
direct_debit_payment/2,3 | direct_debit_payment/1,2 |
direct_debit_cancel/2,3 | direct_debit_cancel/1,2 |
query_beneficiary_name/2,3 | query_beneficiary_name/1,2 |
query_direct_debit/2,3 | query_direct_debit/1,2 |
Transactions.query_status/3 | query_transaction_status/1,2 |
| (unexposed) | reversal/1,2 |
ElixirMpesa.GenerateSessionKey.* | Automatic; ElixirMpesa.session_key/1 if needed |
Six of these keep their names. Where the name is unchanged, the two forms are told apart by the second argument: a binary is the old session key, a keyword list is the new options. Both work during 0.2.x.
Two things now enforced
A payment must carry "input_ThirdPartyConversationID". It is the idempotency key.
The library will not generate one for a payment, because a generated one would give each
retry a fresh key and defeat M-Pesa's duplicate detection. Read-only queries still get one
generated. Use ElixirMpesa.conversation_id/0.
Payments are never retried automatically. 0.1.0 did not retry either, but it is worth stating: a gateway timeout on a payment often means the payment succeeded and only the response was lost. Query the status rather than resending — or resend with the same conversation ID.
Elixir version
The floor is now 1.15, up from a claimed 1.14. Req requires 1.15, and 1.14 was never actually tested.