Skip to content

Instantly share code, notes, and snippets.

@MerNat
Last active February 15, 2024 12:42
Show Gist options
  • Save MerNat/180375707a0a634969621234e3832306 to your computer and use it in GitHub Desktop.
Save MerNat/180375707a0a634969621234e3832306 to your computer and use it in GitHub Desktop.
MPESA Integration using GO (Using till number)
package main
import (
"bytes"
b64 "encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
)
type SafaricomTransactionResponse struct {
MerchantRequestID *string `json:"MerchantRequestID"`
CheckoutRequestID *string `json:"CheckoutRequestID"`
ResponseCode *string `json:"ResponseCode"`
ResponseDescription *string `json:"ResponseDescription"`
CustomerMessage *string `json:"CustomerMessage"`
}
type TransactionRequest struct {
BusinessShortCode string `json:"BusinessShortCode"`
Password string `json:"Password"`
Timestamp string `json:"Timestamp"`
TransactionType string `json:"TransactionType"`
Amount string `json:"Amount"`
PartyA string `json:"PartyA"`
PartyB string `json:"PartyB"`
PhoneNumber string `json:"PhoneNumber"`
CallBackURL string `json:"CallBackURL"`
AccountReference string `json:"AccountReference"`
TransactionDesc string `json:"TransactionDesc"`
}
type AuthResponse struct {
AccessToken string `json:"access_token"`
ExpiresSec string `json:"expires_in"`
}
func main() {
httpClient := http.Client{Timeout: time.Duration(20) * time.Second}
BusinessShortCode := "XXXXXX" //This is the head office number for your buy goods or the store number.
PassKey := "your-key-comes-here" //Pass key from your daraja portal
//Both those values can be captured from your app (daraja portal)
ConsumerKey := "YOUR-CONSUMER-KEY"
ConsumerSecret := "YOUR-CONSUMER-SECRET"
Timestamp := time.Now().UTC().Format("20060102150405")
TransactionType := "CustomerBuyGoodsOnline"
Amount := "1" //Amount to charge
Password := b64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s%s%s", BusinessShortCode, PassKey, Timestamp)))
transactionRequest := TransactionRequest{
BusinessShortCode: BusinessShortCode,
Password: Password,
Timestamp: Timestamp,
TransactionType: TransactionType,
Amount: Amount,
PartyA: "2547xxxxxxxx", //contact to send the request to. (should be the same with PhoneNumber
PartyB: "xxxxxxx", //This is the till number
PhoneNumber: "2547xxxxxxxx", //contact to send the request to
CallBackURL: "https://2ffc-196-202-208-214.eu.ngrok.io/callback", //This is just a callback to test if the transaction is paid or not
AccountReference: "USER_UUID",
TransactionDesc: "Test Payment",
}
req, err := http.NewRequest("GET", "https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials", nil)
if err != nil {
panic(err.Error())
}
authr := fmt.Sprintf("Basic %s", b64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s%s%s", ConsumerKey, ":", ConsumerSecret))))
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", authr)
resp, err := httpClient.Do(req)
if err != nil {
panic(err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
body, _ := ioutil.ReadAll(resp.Body)
panic(string(body))
}
var authResponse AuthResponse
err = json.NewDecoder(resp.Body).Decode(&authResponse)
jsonByte, err := json.Marshal(transactionRequest)
if err != nil {
return
}
req, err = http.NewRequest("POST", "https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest", bytes.NewBuffer(jsonByte))
if err != nil {
panic(err.Error())
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", fmt.Sprintf("%s %s", "Bearer", authResponse.AccessToken))
resp, err = httpClient.Do(req)
if err != nil {
panic(err.Error())
}
defer resp.Body.Close()
var safTran SafaricomTransactionResponse
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err.Error())
}
err = json.Unmarshal(body, &safTran)
fmt.Println(*safTran.CheckoutRequestID)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment