Helpers for parsing STK Push (M-Pesa Express) callback payloads posted by
M-PESA to the merchant's CallBackURL.
STK Push callbacks are one-way notifications: M-PESA only needs the merchant
to acknowledge receipt with ResultCode: 0.
Daraja does not sign callbacks. Verify the request with
Daraja.Callback.Security and deduplicate with Daraja.Callback.Guard before
treating parsed output as proof of payment. Use parse/1 on untrusted input.
Example
with :ok <-
Daraja.Callback.Security.verify(
ip: conn.remote_ip,
check_ip: true,
shared_secret: callback_secret,
provided_secret: conn.params["token"]
),
{:ok, callback} <- Daraja.Express.Callback.parse(payload),
:ok <- Daraja.Callback.Guard.ensure_fresh(callback.checkout_request_id) do
json(conn, Daraja.Express.Callback.accept())
end
Summary
Functions
Builds the JSON response body used to acknowledge an STK Push callback.
Flattens the CallbackMetadata.Item list into %{"Name" => value}.
Parses an STK Push callback payload map into a %Result{} struct.
Parses an STK Push callback map from an untrusted HTTP request.
Functions
@spec accept() :: %{required(String.t()) => String.t() | non_neg_integer()}
Builds the JSON response body used to acknowledge an STK Push callback.
Daraja.Express.Callback.accept()
#=> %{"ResultCode" => 0, "ResultDesc" => "Success"}
Flattens the CallbackMetadata.Item list into %{"Name" => value}.
@spec from_map(map()) :: Daraja.Express.Callback.Result.t()
Parses an STK Push callback payload map into a %Result{} struct.
Successful payloads include a CallbackMetadata block with the transaction
details (Amount, MpesaReceiptNumber, TransactionDate, PhoneNumber). Failed
payloads omit it.
Prefer parse/1 for inbound HTTP requests. from_map/1 accepts only payloads
with a Body.stkCallback envelope.
@spec parse(map()) :: {:ok, Daraja.Express.Callback.Result.t()} | {:error, :invalid_callback, String.t()}
Parses an STK Push callback map from an untrusted HTTP request.
Returns {:error, :invalid_callback, reason} when the top-level shape does
not match a Daraja STK callback.