├── .gitignore ├── .idea ├── vcs.xml ├── modules.xml ├── mpesa-api-go.iml └── workspace.xml ├── .circleci └── config.yml ├── demo └── main.go ├── LICENSE ├── model.go ├── api.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/mpesa-api-go.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Golang CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-go/ for more details 4 | version: 2 5 | jobs: 6 | build: 7 | docker: 8 | # specify the version 9 | - image: circleci/golang:1.9 10 | 11 | # Specify service dependencies here if necessary 12 | # CircleCI maintains a library of pre-built images 13 | # documented at https://circleci.com/docs/2.0/circleci-images/ 14 | # - image: circleci/postgres:9.4 15 | 16 | #### TEMPLATE_NOTE: go expects specific checkout path representing url 17 | #### expecting it in the form of 18 | #### /go/src/github.com/circleci/go-tool 19 | #### /go/src/bitbucket.org/circleci/go-tool 20 | working_directory: /go/src/github.com/AndroidStudyOpenSource/mpesa-api-go 21 | steps: 22 | - checkout 23 | 24 | # specify any bash command here prefixed with `run: ` 25 | - run: go get -v -t -d ./... 26 | - run: go test -v ./... -------------------------------------------------------------------------------- /demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "github.com/AndroidStudyOpenSource/mpesa-api-go" 6 | ) 7 | 8 | const ( 9 | appKey = "GvzjNnYgNJtwgwfLBkZh65VPwfuKvs0V" // sandbox --> change to yours 10 | appSecret = "oOpJICRVlyrGSAkM" // sandbox --> change to yours 11 | ) 12 | 13 | func main() { 14 | // These examples are taken from the mpesa-java-sdk examples 15 | // at https://github.com/safaricom/mpesa-java-sdk 16 | 17 | svc, err := mpesa.New(appKey, appSecret, mpesa.PRODUCTION) 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | res, err := svc.B2BRequest(mpesa.B2B{}) 23 | if err != nil { 24 | log.Println(err) 25 | } 26 | log.Println(res) 27 | 28 | c2b := mpesa.C2B{ 29 | ShortCode: "600576", 30 | CommandID: "CustomerPayBillOnline", 31 | Amount: "2", 32 | Msisdn: "254708374149", 33 | BillRefNumber: "hkjhjkhjkh"} 34 | 35 | res, err = svc.C2BSimulation(c2b) 36 | if err != nil { 37 | log.Println(err) 38 | } 39 | log.Println(res) 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Android Study Open Source 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /model.go: -------------------------------------------------------------------------------- 1 | package mpesa 2 | 3 | type authResponse struct { 4 | AccessToken string `json:"access_token"` 5 | } 6 | 7 | // C2B is a model 8 | type C2B struct { 9 | ShortCode string 10 | CommandID string 11 | Amount string 12 | Msisdn string 13 | BillRefNumber string 14 | } 15 | 16 | // B2C is a model 17 | type B2C struct { 18 | InitiatorName string 19 | SecurityCredential string 20 | CommandID string 21 | Amount string 22 | PartyA string 23 | PartyB string 24 | Remarks string 25 | QueueTimeOutURL string 26 | ResultURL string 27 | Occassion string 28 | } 29 | 30 | // B2B is a model 31 | type B2B struct { 32 | Initiator string 33 | SecurityCredential string 34 | CommandID string 35 | SenderIdentifierType string 36 | RecieverIdentifierType string 37 | Amount string 38 | PartyA string 39 | PartyB string 40 | Remarks string 41 | AccountReference string 42 | QueueTimeOutURL string 43 | ResultURL string 44 | } 45 | 46 | // Express is a model 47 | type Express struct { 48 | BusinessShortCode string 49 | Password string 50 | Timestamp string 51 | TransactionType string 52 | Amount string 53 | PartyA string 54 | PartyB string 55 | PhoneNumber string 56 | CallBackURL string 57 | AccountReference string 58 | TransactionDesc string 59 | } 60 | 61 | // Reversal is a model 62 | type Reversal struct { 63 | Initiator string 64 | SecurityCredential string 65 | CommandID string 66 | TransactionID string 67 | Amount string 68 | ReceiverParty string 69 | ReceiverIdentifierType string 70 | QueueTimeOutURL string 71 | ResultURL string 72 | Remarks string 73 | Occassion string 74 | } 75 | 76 | // BalanceInquiry is a model 77 | type BalanceInquiry struct { 78 | Initiator string 79 | SecurityCredential string 80 | CommandID string 81 | PartyA string 82 | IdentifierType string 83 | Remarks string 84 | QueueTimeOutURL string 85 | ResultURL string 86 | } 87 | 88 | // Pull is a model 89 | type Pull struct { 90 | ShortCode string 91 | StartDate string 92 | EndDate string 93 | PageNumber string 94 | } 95 | 96 | // RegisterURL is a model 97 | type C2BRegisterURL struct { 98 | ShortCode string 99 | ResponseType string 100 | ConfirmationURL string 101 | ValidationURL string 102 | } 103 | -------------------------------------------------------------------------------- /api.go: -------------------------------------------------------------------------------- 1 | package mpesa 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "net/http" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | // Env is the environment type 15 | type Env string 16 | 17 | const ( 18 | // DEV is the development env tag 19 | 20 | // SANDBOX is the sandbox env tag 21 | SANDBOX = iota 22 | // PRODUCTION is the production env tag 23 | PRODUCTION 24 | ) 25 | 26 | // Service is an Mpesa Service 27 | type Service struct { 28 | AppKey string 29 | AppSecret string 30 | Env int 31 | } 32 | 33 | // New return a new Mpesa Service 34 | func New(appKey, appSecret string, env int) (Service, error) { 35 | return Service{appKey, appSecret, env}, nil 36 | } 37 | 38 | //Generate Mpesa Daraja Access Token 39 | func (s Service) auth() (string, error) { 40 | b := []byte(s.AppKey + ":" + s.AppSecret) 41 | encoded := base64.StdEncoding.EncodeToString(b) 42 | 43 | url := s.baseURL() + "oauth/v1/generate?grant_type=client_credentials" 44 | req, err := http.NewRequest(http.MethodGet, url, strings.NewReader(encoded)) 45 | if err != nil { 46 | return "", err 47 | } 48 | req.Header.Add("authorization", "Basic "+encoded) 49 | req.Header.Add("cache-control", "no-cache") 50 | 51 | client := &http.Client{Timeout: 60 * time.Second} 52 | res, err := client.Do(req) 53 | if res != nil { 54 | defer res.Body.Close() 55 | } 56 | if err != nil { 57 | return "", fmt.Errorf("could not send auth request: %v", err) 58 | } 59 | 60 | var authResponse authResponse 61 | err = json.NewDecoder(res.Body).Decode(&authResponse) 62 | if err != nil { 63 | return "", fmt.Errorf("could not decode auth response: %v", err) 64 | } 65 | 66 | accessToken := authResponse.AccessToken 67 | return accessToken, nil 68 | } 69 | 70 | // Simulation requests user device for payment 71 | func (s Service) Simulation(express Express) (string, error) { 72 | body, err := json.Marshal(express) 73 | if err != nil { 74 | return "", nil 75 | } 76 | auth, err := s.auth() 77 | if err != nil { 78 | return "", nil 79 | } 80 | 81 | headers := make(map[string]string) 82 | headers["content-type"] = "application/json" 83 | headers["authorization"] = "Bearer " + auth 84 | headers["cache-control"] = "no-cache" 85 | 86 | url := s.baseURL() + "mpesa/stkpush/v1/processrequest" 87 | return s.newReq(url, body, headers) 88 | } 89 | 90 | // TransactionStatus gets status of a transaction 91 | func (s Service) TransactionStatus(express Express) (string, error) { 92 | body, err := json.Marshal(express) 93 | if err != nil { 94 | return "", nil 95 | } 96 | 97 | auth, err := s.auth() 98 | if err != nil { 99 | return "", nil 100 | } 101 | 102 | headers := make(map[string]string) 103 | headers["Content-Type"] = "application/json" 104 | headers["Authorization"] = "Bearer " + auth 105 | 106 | url := s.baseURL() + "mpesa/stkpushquery/v1/query" 107 | return s.newReq(url, body, headers) 108 | } 109 | 110 | // C2BRegisterURL requests 111 | func (s Service) C2BRegisterURL(c2bRegisterURL C2BRegisterURL) (string, error) { 112 | body, err := json.Marshal(c2bRegisterURL) 113 | if err != nil { 114 | return "", err 115 | } 116 | 117 | auth, err := s.auth() 118 | if err != nil { 119 | return "", nil 120 | } 121 | 122 | headers := make(map[string]string) 123 | headers["Content-Type"] = "application/json" 124 | headers["Authorization"] = "Bearer " + auth 125 | headers["Cache-Control"] = "no-cache" 126 | 127 | url := s.baseURL() + "mpesa/c2b/v1/registerurl" 128 | return s.newReq(url, body, headers) 129 | } 130 | 131 | // C2BSimulation sends a new request 132 | func (s Service) C2BSimulation(c2b C2B) (string, error) { 133 | body, err := json.Marshal(c2b) 134 | if err != nil { 135 | return "", err 136 | } 137 | 138 | auth, err := s.auth() 139 | if err != nil { 140 | return "", nil 141 | } 142 | 143 | headers := make(map[string]string) 144 | headers["Content-Type"] = "application/json" 145 | headers["Authorization"] = "Bearer " + auth 146 | headers["cache-control"] = "no-cache" 147 | 148 | url := s.baseURL() + "mpesa/c2b/v1/simulate" 149 | return s.newReq(url, body, headers) 150 | } 151 | 152 | // B2CRequest sends a new request 153 | func (s Service) B2CRequest(b2c B2C) (string, error) { 154 | body, err := json.Marshal(b2c) 155 | if err != nil { 156 | return "", err 157 | } 158 | 159 | auth, err := s.auth() 160 | if err != nil { 161 | return "", nil 162 | } 163 | 164 | headers := make(map[string]string) 165 | headers["Content-Type"] = "application/json" 166 | headers["Authorization"] = "Bearer " + auth 167 | headers["cache-control"] = "no-cache" 168 | 169 | url := s.baseURL() + "mpesa/b2c/v1/paymentrequest" 170 | return s.newReq(url, body, headers) 171 | } 172 | 173 | // B2BRequest sends a new request 174 | func (s Service) B2BRequest(b2b B2B) (string, error) { 175 | body, err := json.Marshal(b2b) 176 | if err != nil { 177 | return "", nil 178 | } 179 | auth, err := s.auth() 180 | if err != nil { 181 | return "", nil 182 | } 183 | 184 | headers := make(map[string]string) 185 | headers["Content-Type"] = "application/json" 186 | headers["Authorization"] = "Bearer " + auth 187 | headers["cache-control"] = "no-cache" 188 | 189 | url := s.baseURL() + "mpesa/b2b/v1/paymentrequest" 190 | return s.newReq(url, body, headers) 191 | } 192 | 193 | // Reversal requests a reversal? 194 | func (s Service) Reversal(reversal Reversal) (string, error) { 195 | body, err := json.Marshal(reversal) 196 | if err != nil { 197 | return "", err 198 | } 199 | 200 | auth, err := s.auth() 201 | if err != nil { 202 | return "", nil 203 | } 204 | 205 | headers := make(map[string]string) 206 | headers["Content-Type"] = "application/json" 207 | headers["Authorization"] = "Bearer " + auth 208 | headers["cache-control"] = "no-cache" 209 | 210 | url := s.baseURL() + "safaricom/reversal/v1/request" //TODO :: CONFIRM THIS URL/ENDPOINT??? 211 | return s.newReq(url, body, headers) 212 | } 213 | 214 | // BalanceInquiry sends a balance inquiry 215 | func (s Service) BalanceInquiry(balanceInquiry BalanceInquiry) (string, error) { 216 | auth, err := s.auth() 217 | if err != nil { 218 | return "", nil 219 | } 220 | 221 | body, err := json.Marshal(balanceInquiry) 222 | if err != nil { 223 | return "", err 224 | } 225 | 226 | headers := make(map[string]string) 227 | headers["Content-Type"] = "application/json" 228 | headers["Authorization"] = "Bearer " + auth 229 | headers["cache-control"] = "no-cache" 230 | headers["postman-token"] = "2aa448be-7d56-a796-065f-b378ede8b136" 231 | 232 | url := s.baseURL() + "mpesa/accountbalance/v1/query" 233 | return s.newReq(url, body, headers) 234 | } 235 | 236 | // BalanceInquiry sends a balance inquiry 237 | func (s Service) PullTransactions(pull Pull) (string, error) { 238 | auth, err := s.auth() 239 | if err != nil { 240 | return "", nil 241 | } 242 | 243 | body, err := json.Marshal(pull) 244 | if err != nil { 245 | return "", err 246 | } 247 | 248 | headers := make(map[string]string) 249 | headers["Content-Type"] = "application/json" 250 | headers["Authorization"] = "Bearer " + auth 251 | headers["cache-control"] = "no-cache" 252 | 253 | url := s.baseURL() + "pulltransactions/v1/query" 254 | return s.newReq(url, body, headers) 255 | } 256 | 257 | func (s Service) newReq(url string, body []byte, headers map[string]string) (string, error) { 258 | request, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body)) 259 | if err != nil { 260 | return "", nil 261 | } 262 | 263 | for key, value := range headers { 264 | request.Header.Set(key, value) 265 | } 266 | 267 | client := &http.Client{Timeout: 60 * time.Second} 268 | res, err := client.Do(request) 269 | if res != nil { 270 | defer res.Body.Close() 271 | } 272 | if err != nil { 273 | return "", err 274 | } 275 | 276 | stringBody, err := ioutil.ReadAll(res.Body) 277 | if err != nil { 278 | return "", err 279 | } 280 | 281 | return string(stringBody), nil 282 | } 283 | 284 | func (s Service) baseURL() string { 285 | if s.Env == PRODUCTION { 286 | return "https://api.safaricom.co.ke/" 287 | } 288 | return "https://sandbox.safaricom.co.ke/" 289 | } 290 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MPESA Golang API Wrapper [![CircleCI](https://circleci.com/gh/AndroidStudyOpenSource/mpesa-api-go.svg?style=shield)](https://circleci.com/gh/AndroidStudyOpenSource/mpesa-api-go) [![Maintainability](https://api.codeclimate.com/v1/badges/54dcfdfde1daf230516f/maintainability)](https://codeclimate.com/github/AndroidStudyOpenSource/mpesa-api-go/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/54dcfdfde1daf230516f/test_coverage)](https://codeclimate.com/github/AndroidStudyOpenSource/mpesa-api-go/test_coverage) 2 | 3 | 4 | The wrapper provides convenient access to the [Safaricom MPESA Daraja API](https://developer.safaricom.co.ke/apis-explorer) for applications written in server-side Golang. :rocket: 5 | 6 | ## Installing 7 | You can install the package by running: 8 | 9 | ``` 10 | go get github.com/AndroidStudyOpenSource/mpesa-api-go 11 | ``` 12 | 13 | ## Usage 14 | The package needs to be configured with your **appKey** and **appSecret** which can be obtained from Safaricom. 15 | 16 | ``` 17 | const ( 18 | appKey = "YOUR_APP_KEY" 19 | appSecret = "YOUR_APP_SECRET" 20 | ) 21 | ``` 22 | 23 | The following examples with show you how to make requests to the various api's available. 24 | 25 | ### MPESAExpress (Formerly STKPush) 26 | This api allows you to do Lipa Na M-Pesa payment using STK Push. This is a simple example: 27 | ```go 28 | package main 29 | 30 | import ( 31 | "log" 32 | "github.com/AndroidStudyOpenSource/mpesa-api-go" 33 | ) 34 | 35 | const ( 36 | appKey = "" 37 | appSecret = "" 38 | ) 39 | 40 | func main() { 41 | 42 | svc, err := mpesa.New(appKey, appSecret, mpesa.SANDBOX) 43 | if err != nil { 44 | panic(err) 45 | } 46 | 47 | res, err := svc.Simulation(mpesa.Express{ 48 | BusinessShortCode: "", 49 | Password: "", 50 | Timestamp: "", 51 | TransactionType: "", 52 | Amount: "", 53 | PartyA: "", 54 | PartyB: "", 55 | PhoneNumber: "", 56 | CallBackURL: "", 57 | AccountReference: "", 58 | TransactionDesc: "", 59 | }) 60 | 61 | if err != nil { 62 | log.Println(err) 63 | } 64 | log.Println(res) 65 | 66 | } 67 | 68 | ``` 69 | 70 | ### C2B 71 | This api allows you to register C2B Callback URLs to Safaricom, and also Simulate a C2B Transaction in ```Sandbox``` 72 | 73 | This is a simple demo to show how to register C2B Callback URL: 74 | 75 | ```go 76 | package main 77 | 78 | import ( 79 | "log" 80 | "github.com/AndroidStudyOpenSource/mpesa-api-go" 81 | ) 82 | 83 | const ( 84 | appKey = "" 85 | appSecret = "" 86 | ) 87 | 88 | func main() { 89 | 90 | svc, err := mpesa.New(appKey, appSecret, mpesa.SANDBOX) 91 | if err != nil { 92 | panic(err) 93 | } 94 | 95 | res, err := svc.C2BRegisterURL(mpesa.C2BRegisterURL{ 96 | ShortCode: "", 97 | ResponseType: "", 98 | ConfirmationURL: "", 99 | ValidationURL: "", 100 | }) 101 | 102 | if err != nil { 103 | log.Println(err) 104 | } 105 | log.Println(res) 106 | 107 | } 108 | 109 | ``` 110 | To simulate a C2B Request, use this simple example: 111 | 112 | ```go 113 | package main 114 | 115 | import ( 116 | "log" 117 | "github.com/AndroidStudyOpenSource/mpesa-api-go" 118 | ) 119 | 120 | const ( 121 | appKey = "" 122 | appSecret = "" 123 | ) 124 | 125 | func main() { 126 | 127 | svc, err := mpesa.New(appKey, appSecret, mpesa.SANDBOX) 128 | if err != nil { 129 | panic(err) 130 | } 131 | 132 | res, err := svc.C2BSimulation(mpesa.C2B{ 133 | ShortCode: "", 134 | CommandID: "", 135 | Amount: "", 136 | Msisdn: "", 137 | BillRefNumber: "", 138 | }) 139 | 140 | if err != nil { 141 | log.Println(err) 142 | } 143 | log.Println(res) 144 | 145 | } 146 | ``` 147 | 148 | ### B2C 149 | This api allows you to do M-Pesa Transaction from company to client. 150 | 151 | ```go 152 | package main 153 | 154 | import ( 155 | "log" 156 | "github.com/AndroidStudyOpenSource/mpesa-api-go" 157 | ) 158 | 159 | const ( 160 | appKey = "" 161 | appSecret = "" 162 | ) 163 | 164 | func main() { 165 | 166 | svc, err := mpesa.New(appKey, appSecret, mpesa.SANDBOX) 167 | if err != nil { 168 | panic(err) 169 | } 170 | 171 | res, err := svc.B2CRequest(mpesa.B2C{ 172 | InitiatorName: "", 173 | SecurityCredential: "", 174 | CommandID: "", 175 | Amount: "", 176 | PartyA: "", 177 | PartyB: "", 178 | Remarks: "", 179 | QueueTimeOutURL: "", 180 | ResultURL: "", 181 | Occassion: "", 182 | }) 183 | 184 | if err != nil { 185 | log.Println(err) 186 | } 187 | log.Println(res) 188 | 189 | } 190 | ``` 191 | 192 | ### B2B 193 | This api allows you to do M-Pesa Transaction from one company to another. 194 | 195 | ```go 196 | package main 197 | 198 | import ( 199 | "log" 200 | "github.com/AndroidStudyOpenSource/mpesa-api-go" 201 | ) 202 | 203 | const ( 204 | appKey = "" 205 | appSecret = "" 206 | ) 207 | 208 | func main() { 209 | 210 | svc, err := mpesa.New(appKey, appSecret, mpesa.SANDBOX) 211 | if err != nil { 212 | panic(err) 213 | } 214 | 215 | res, err := svc.B2BRequest(mpesa.B2B{ 216 | Initiator: "", 217 | SecurityCredential: "", 218 | CommandID: "", 219 | SenderIdentifierType: "", 220 | RecieverIdentifierType: "", 221 | Remarks: "", 222 | Amount: "", 223 | PartyA: "", 224 | PartyB: "", 225 | AccountReference: "", 226 | QueueTimeOutURL: "", 227 | ResultURL: "", 228 | }) 229 | 230 | if err != nil { 231 | log.Println(err) 232 | } 233 | log.Println(res) 234 | 235 | } 236 | 237 | ``` 238 | 239 | ### Account Balance 240 | This api allows you to do balance inquiry. 241 | 242 | ```go 243 | package main 244 | 245 | import ( 246 | "log" 247 | "github.com/AndroidStudyOpenSource/mpesa-api-go" 248 | ) 249 | 250 | const ( 251 | appKey = "" 252 | appSecret = "" 253 | ) 254 | 255 | func main() { 256 | 257 | svc, err := mpesa.New(appKey, appSecret, mpesa.SANDBOX) 258 | if err != nil { 259 | panic(err) 260 | } 261 | 262 | res, err := svc.BalanceInquiry(mpesa.BalanceInquiry{ 263 | Initiator: "", 264 | SecurityCredential: "", 265 | CommandID: "", 266 | PartyA: "", 267 | IdentifierType: "", 268 | Remarks: "", 269 | QueueTimeOutURL: "", 270 | ResultURL: "", 271 | }) 272 | 273 | if err != nil { 274 | log.Println(err) 275 | } 276 | log.Println(res) 277 | 278 | } 279 | ``` 280 | 281 | ### Transaction Status 282 | This api allows you to check the status of transaction. 283 | 284 | ### Reversal 285 | This api allows you to do a transaction reversal 286 | 287 | ```go 288 | package main 289 | 290 | import ( 291 | "log" 292 | "github.com/AndroidStudyOpenSource/mpesa-api-go" 293 | ) 294 | 295 | const ( 296 | appKey = "" 297 | appSecret = "" 298 | ) 299 | 300 | func main() { 301 | 302 | svc, err := mpesa.New(appKey, appSecret, mpesa.SANDBOX) 303 | if err != nil { 304 | panic(err) 305 | } 306 | 307 | res, err := svc.Reversal(mpesa.Reversal{ 308 | Initiator: "", 309 | SecurityCredential: "", 310 | CommandID: "", 311 | TransactionID: "", 312 | Amount: "", 313 | ReceiverParty: "", 314 | ReceiverIdentifierType: "", 315 | QueueTimeOutURL: "", 316 | ResultURL: "", 317 | Remarks: "", 318 | Occassion: "", 319 | }) 320 | 321 | if err != nil { 322 | log.Println(err) 323 | } 324 | log.Println(res) 325 | 326 | } 327 | ``` 328 | 329 | ### Contributing 330 | 331 | We’re glad you’re interested in MPESA Daraja Golang SDK, and we’d love to see where you take it. If you would like to contribute code to this project you can do so through GitHub by Forking the Repository and creating a Pull Request. 332 | 333 | When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. We look forward to you submitting a Pull Request. 334 | 335 | Use [gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows#gitflow-workflow). 336 | Always tag releases to `develop` and `master`. 337 | 338 | Thanks, and please do take it for a joyride! 339 | 340 | ### License 341 | 342 | ```text 343 | MIT License 344 | 345 | Copyright (c) 2018 Android Study Open Source 346 | 347 | Permission is hereby granted, free of charge, to any person obtaining a copy 348 | of this software and associated documentation files (the "Software"), to deal 349 | in the Software without restriction, including without limitation the rights 350 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 351 | copies of the Software, and to permit persons to whom the Software is 352 | furnished to do so, subject to the following conditions: 353 | 354 | The above copyright notice and this permission notice shall be included in all 355 | copies or substantial portions of the Software. 356 | 357 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 358 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 359 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 360 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 361 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 362 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 363 | SOFTWARE. 364 | ``` 365 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 82 | 83 | 91 | 92 | 93 | 94 | 95 | true 96 | DEFINITION_ORDER 97 | 98 | 99 | 100 | 101 | 102 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 |