Daraja.Express.Callback (daraja v0.1.0)

Copy Markdown View Source

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

accept()

@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"}

callback_metadata_map(items)

@spec callback_metadata_map([map()] | nil) :: %{optional(String.t()) => term()}

Flattens the CallbackMetadata.Item list into %{"Name" => value}.

from_map(map)

@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.

parse(map)

@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.