Skip to content

Parse M-Pesa STK Push callbacks - #54

Open
FrankCidney wants to merge 6 commits into
Flying-Tea-Squad:mainfrom
FrankCidney:feat/stk-callback-parser
Open

FrankCidney wants to merge 6 commits into
Flying-Tea-Squad:mainfrom
FrankCidney:feat/stk-callback-parser

Conversation

@FrankCidney

Copy link
Copy Markdown

What this solves

M-Pesa sends the final outcome of an STK Push payment as a nested callback whose payment details are stored in a name/value metadata list. Applications currently have to decode that provider-specific structure themselves and distinguish malformed payloads from valid unsuccessful payment outcomes.

This adds a focused parser that converts the callback into a structured Go result while preserving provider metadata.

What changed

  • Added ParseSTKPushCallback and STKPushCallbackResult in the mpesa package.
  • Extracted result details, request correlation IDs, amount, M-Pesa receipt number, and customer phone number.
  • Normalized numeric or quoted phone numbers to strings and preserved all callback metadata as reference data.
  • Treated nonzero M-Pesa result codes as valid payment outcomes rather than parser errors.
  • Added validation for malformed envelopes, missing successful-payment fields, invalid metadata values, and duplicate metadata names.
  • Added table-driven coverage for successful, unsuccessful, reordered, unknown, and malformed callback data.

Testing

  • go test ./mpesa -count=1
  • go test ./...
  • go test -race ./mpesa -count=1
  • go vet ./...
  • golangci-lint run ./...

Related issue

Closes #18

@carsonak carsonak left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Check out the changes I suggested, push the changes to this PR and mark the changes as resolved so that I can merge this PR.

Comment thread mpesa/callback.go Outdated
if err := json.Unmarshal(item.Value, &referenceValue); err != nil {
return fmt.Errorf("metadata item %q has invalid Value: %w", item.Name, err)
}
result.ReferenceData[item.Name] = referenceValue

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of decoding unknown fields, we should preserve the original json values as json.RawMessage in the STKPushCallbackResult.ReferenceData map. We can leave the decoding to the users, as they might have more information about the type of the values.

Comment thread mpesa/callback.go
if callback.CallbackMetadata == nil {
// Failed payments normally omit metadata because no transaction was
// completed. A successful result cannot satisfy the public contract
// without its amount, receipt number, and customer number.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Successful callbacks will always have all the named fields field out". Mention this in the ParseSTKPushCallback function documentation or the STKPushCallbackResult struct documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement STK Push callback parsing

2 participants