Add webhooks support and mpesa

Signed-off-by: GitHub <noreply@github.com>
This commit is contained in:
b1ackd0t
2022-07-17 16:58:55 +00:00
committed by GitHub
parent 05010188f4
commit 4c5fb21750
6 changed files with 456 additions and 181 deletions
+1
View File
@@ -1,2 +1,3 @@
# kopokopo-go
Unofficial Golang SDK to connect to the Kopo Kopo API https://developers.kopokopo.com/
+6 -5
View File
@@ -10,6 +10,7 @@ import (
var tokenEndpoint = "oauth"
// https://sandbox.kopokopo.com/oauth/token?grant_type=client_credentials&client_id={{CLIENT-ID}}&client_secret={{CLIENT-SECRET}}
func (sdk kSDK) GetToken() (string, error) {
q := url.Values{}
q.Add("client_id", sdk.credentials.AppID)
@@ -21,7 +22,7 @@ func (sdk kSDK) GetToken() (string, error) {
if err != nil {
return "", err
}
resp, err := sdk.makeRequest(req, "")
resp, err := sdk.getBodyParams(req, "")
if err != nil {
return "", err
}
@@ -47,7 +48,7 @@ func (sdk kSDK) RevokeToken(token string) error {
if err != nil {
return err
}
_, err = sdk.makeRequest(req, "")
_, err = sdk.getBodyParams(req, "")
if err != nil {
return err
}
@@ -62,13 +63,13 @@ func (sdk kSDK) TokenIntrospection(token string) (tokenIntrospectionResp, error)
q.Add("client_id", sdk.credentials.AppID)
q.Add("client_secret", sdk.credentials.Secret)
q.Add("token", token)
endpoint := fmt.Sprintf("%s/%s/token/info?%s", sdk.baseURL, tokenEndpoint, q.Encode())
endpoint := fmt.Sprintf("%s/%s/token/introspect?%s", sdk.baseURL, tokenEndpoint, q.Encode())
req, err := http.NewRequest(http.MethodPost, endpoint, nil)
if err != nil {
return tokenIntrospectionResp{}, err
}
resp, err := sdk.makeRequest(req, "")
resp, err := sdk.getBodyParams(req, "")
if err != nil {
return tokenIntrospectionResp{}, err
}
@@ -90,7 +91,7 @@ func (sdk kSDK) TokenInformation(token string) (tokenInfo, error) {
if err != nil {
return tokenInfo{}, err
}
resp, err := sdk.makeRequest(req, token)
resp, err := sdk.getBodyParams(req, token)
if err != nil {
return tokenInfo{}, err
}
+57 -2
View File
@@ -1,6 +1,7 @@
package kopokopo
import (
"errors"
"io/ioutil"
"net/http"
"time"
@@ -31,6 +32,40 @@ type SDK interface {
// Shows details about the token used for authentication.
TokenInformation(token string) (tokenInfo, error)
// Create a webhook subscription
CreateWebhook(token string, webookReq CreateWebhookReq) (string, error)
// Before processing webhook events, make sure that they originated from Kopo Kopo.
// Each request is signed with the api_key you got when creating an oauth application on the platform.
ValidateWebhook(webhookURL string) (BuyGoodsTrans, error)
// Notifies your application when a Buygoods Transaction has been received.
C2BSubscription(webhookURL string) (BuyGoodsTrans, error)
// Notifies your application when a B2b (External Till to Till transaction) has been received.
// These are payments recieved from other tills and not subscribers.
B2BSubscription(webhookURL string) (BuyGoodsTrans, error)
// Notifies your application when another Kopo Kopo merchant transfers funds
// to your Kopo Kopo merchant account (Merchant to Merchant)
M2MSubscription(webhookURL string) (BuyGoodsTrans, error)
// Notifies your application when a Buygoods Transaction has been reversed
C2BReversalSubscription(webhookURL string) (BuyGoodsTrans, error)
// Settlement Transfer Completed
SettlementSub(webhookURL string) (BuyGoodsTrans, error)
// Customer Created
CusomerCreationSub(webhookURL string) (CustomerReq, error)
// Receive payments from M-PESA users via STK Push.
ReceiveMpesaPayment(token string, receiveMpesaReq ReceiveMpesaReq) (string, error)
// With an Incoming Payment location url, you can query what the status of the Incoming Payment is.
// If a corresponding Incoming Payment Result exists, it will be bundled in the payload of the result.
QueryIncommingMpesaPayment(token, id string) (IncomingPaymentEvent, error)
}
// Credentials contains the credentials
@@ -68,15 +103,23 @@ func NewSDK(conf Config) SDK {
}
}
func (sdk kSDK) makeRequest(req *http.Request, token string) ([]byte, error) {
func (sdk kSDK) makeRequest(req *http.Request, token string) (*http.Response, error) {
if token != "" {
req.Header.Add("Authorization", "Basic "+token)
req.Header.Add("Authorization", "Bearer "+token)
}
req.Header.Add("Content-Type", "application/json")
resp, err := sdk.client.Do(req)
if err != nil {
return nil, err
}
return resp, nil
}
func (sdk kSDK) getBodyParams(req *http.Request, token string) ([]byte, error) {
resp, err := sdk.makeRequest(req, token)
if err != nil {
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
@@ -84,3 +127,15 @@ func (sdk kSDK) makeRequest(req *http.Request, token string) ([]byte, error) {
defer resp.Body.Close()
return body, nil
}
func (sdk kSDK) getHeaderParams(req *http.Request, token string) (string, error) {
resp, err := sdk.makeRequest(req, token)
if err != nil {
return "", err
}
if resp.StatusCode != http.StatusCreated {
return "", errors.New("failed to created")
}
id := resp.Header.Get("Location")
return id, nil
}
+50 -7
View File
@@ -1,14 +1,57 @@
package kopokopo
// Receive payments from M-PESA users via STK Push.
// func (sdk kSDK) ReceiveMpesaPayment(grantType string) (string, error) {
// panic("Not implemented")
// }
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
)
func (sdk kSDK) ReceiveMpesaPayment(token string, receiveMpesaReq ReceiveMpesaReq) (string, error) {
if err := receiveMpesaReq.Validate(); err != nil {
return "", err
}
data, err := json.Marshal(receiveMpesaReq)
if err != nil {
return "", err
}
endpoint := fmt.Sprintf("%s/api/v1/incoming_payments", sdk.baseURL)
req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewReader(data))
if err != nil {
return "", err
}
url, err := sdk.getHeaderParams(req, token)
if err != nil {
return "", err
}
id := strings.TrimPrefix(url, fmt.Sprintf("%s/api/v1/incoming_payments/", sdk.baseURL))
return id, nil
}
// func (sdk kSDK) ProcessIncommingMpesaPayment(grantType string) (string, error) {
// panic("Not implemented")
// }
// func (sdk kSDK) QueryIncommingMpesaPayment(grantType string) (string, error) {
// panic("Not implemented")
// }
func (sdk kSDK) QueryIncommingMpesaPayment(token, id string) (IncomingPaymentEvent, error) {
if id == "" {
return IncomingPaymentEvent{}, errors.New("empty id")
}
endpoint := fmt.Sprintf("%s/api/v1/incoming_payments/", sdk.baseURL)
req, err := http.NewRequest(http.MethodGet, endpoint, nil)
if err != nil {
return IncomingPaymentEvent{}, err
}
resp, err := sdk.getBodyParams(req, token)
if err != nil {
return IncomingPaymentEvent{}, err
}
var ipe IncomingPaymentEvent
if err := json.Unmarshal(resp, &ipe); err != nil {
return ipe, err
}
return ipe, nil
}
+181 -136
View File
@@ -1,161 +1,206 @@
package kopokopo
// type CreateWebhookReq struct {
// EventType string `json:"event_type,omitempty"` //The type of event you are subscribing to
// URL string `json:"url,omitempty"` // The http end point to send the webhook.
// Scope string `json:"scope,omitempty"` // The scope of the webhook subscription.
// ScopeRef string `json:"scope_reference,omitempty"`
// }
import (
"errors"
"strings"
)
// func (cwr CreateWebhookReq) Validate() error {
// if cwr.EventType != "buygoods_transaction_received" &&
// cwr.EventType != "buygoods_transaction_reversed" &&
// cwr.EventType != "b2b_transaction_received" &&
// cwr.EventType != "m2m_transaction_received" &&
// cwr.EventType != "settlement_transfer_completed" &&
// cwr.EventType != "customer_created" {
// return errors.New("invalid event type")
// }
// if !strings.HasPrefix(cwr.URL, "https") {
// return errors.New("URL is not secured with TLS")
// }
// if cwr.Scope != "company" && cwr.Scope != "till" {
// return errors.New("invalid scope")
// }
// if cwr.Scope == "till" && cwr.ScopeRef == "" {
// return errors.New("scope reference is required")
// }
// return nil
// }
// CreateWebhookReq struct
type CreateWebhookReq struct {
EventType string `json:"event_type,omitempty"` //The type of event you are subscribing to
URL string `json:"url,omitempty"` // The http end point to send the webhook.
Scope string `json:"scope,omitempty"` // The scope of the webhook subscription.
ScopeRef string `json:"scope_reference,omitempty"`
}
// type Destination struct {
// Type string `json:"type,omitempty"`
// Resource DestinationResource `json:"resource,omitempty"`
// }
// Validate returns nil if the struct is valid
func (cwr CreateWebhookReq) Validate() error {
if cwr.EventType != "buygoods_transaction_received" &&
cwr.EventType != "buygoods_transaction_reversed" &&
cwr.EventType != "b2b_transaction_received" &&
cwr.EventType != "m2m_transaction_received" &&
cwr.EventType != "settlement_transfer_completed" &&
cwr.EventType != "customer_created" {
return errors.New("invalid event type")
}
if !strings.HasPrefix(cwr.URL, "https") {
return errors.New("URL is not secured with TLS")
}
if cwr.Scope != "company" && cwr.Scope != "till" {
return errors.New("invalid scope")
}
if cwr.Scope == "till" && cwr.ScopeRef == "" {
return errors.New("scope reference is required")
}
return nil
}
// type DestinationResource struct {
// Reference string `json:"reference,omitempty"` // The destination reference
// AccountName string `json:"account_name,omitempty"` // The name as indicated on the bank account
// AccountNumber string `json:"account_number,omitempty"` // The bank account number
// BankBranchReference string `json:"bank_branch_ref,omitempty"` // An identifier identifying the destination bank branch
// SettlementMethod string `json:"settlement_method,omitempty"` // EFT or RTS
// FirstName string `json:"first_name,omitempty"` // String First name of the recipient
// LastName string `json:"last_name,omitempty"` // Last name of recipient
// Email string `json:"email,omitempty"` // Email of recipient
// PhoneNumber string `json:"phone_number,omitempty"` // Phone number
// Network string `json:"network,omitempty"` // The mobile network to which the phone number belongs
// }
// Destination struct
type Destination struct {
Type string `json:"type,omitempty"`
Resource DestinationResource `json:"resource,omitempty"`
}
// type Disbursements struct {
// Status string `json:"status,omitempty"` // The status of the disbursement
// Amount string `json:"amount,omitempty"` // The amount of the disbursement
// OriginationTime string `json:"origination_time,omitempty"` // The Timestamp of when the transaction took place
// TransactionalReference string `json:"transactional_reference,omitempty"` // The reference from the transaction. i.e mpesa reference It is null for eft transactions
// }
// DestinationResource struct
type DestinationResource struct {
Reference string `json:"reference,omitempty"` // The destination reference
AccountName string `json:"account_name,omitempty"` // The name as indicated on the bank account
AccountNumber string `json:"account_number,omitempty"` // The bank account number
BankBranchReference string `json:"bank_branch_ref,omitempty"` // An identifier identifying the destination bank branch
SettlementMethod string `json:"settlement_method,omitempty"` // EFT or RTS
FirstName string `json:"first_name,omitempty"` // String First name of the recipient
LastName string `json:"last_name,omitempty"` // Last name of recipient
Email string `json:"email,omitempty"` // Email of recipient
PhoneNumber string `json:"phone_number,omitempty"` // Phone number
Network string `json:"network,omitempty"` // The mobile network to which the phone number belongs
}
// type Resource struct {
// ID string `json:"id,omitempty"` // The api reference of the transaction
// Amount float64 `json:"amount,omitempty"` // The amount of the transaction
// Status string `json:"status,omitempty"` // The status of the transaction
// System string `json:"system,omitempty"` // The mobile money system
// Currency string `json:"currency,omitempty"` // Currency
// Reference string `json:"reference,omitempty"` // The mpesa reference
// TransactionalReference string `json:"transactional_reference,omitempty"`
// TillNumber string `json:"till_number,omitempty"` // The till number to which the payment was made
// SendingTill string `json:"sending_till,omitempty"` // The till number of the sender
// AccountName string `json:"account_name,omitempty"`
// AccountNumber string `json:"account_number,omitempty"`
// BankBranchReference string `json:"bank_branch_ref,omitempty"`
// SettlementMethod string `json:"settlement_method,omitempty"`
// SendingMerchant string `json:"sending_merchant,omitempty"` // Name of merchant
// SenderPhoneNumber string `json:"sender_phone_number,omitempty"` // The phone number that sent the payment
// OriginationTime string `json:"origination_time,omitempty"` // The transaction timestamp
// SenderLastName string `json:"sender_last_name,omitempty"` // Last name of payer
// SenderFirstName string `json:"sender_first_name,omitempty"` // First name of payer
// SenderMiddleName string `json:"sender_middle_name,omitempty"` // Middle name of payer
// Destination Destination `json:"destination,omitempty"` // The destination of the settlement transfer
// Disbursements []Disbursements `json:"disbursements,omitempty"` // These are the disbursements in that particular transfer batch
// }
// Disbursements struct
type Disbursements struct {
Status string `json:"status,omitempty"` // The status of the disbursement
Amount string `json:"amount,omitempty"` // The amount of the disbursement
OriginationTime string `json:"origination_time,omitempty"` // The Timestamp of when the transaction took place
TransactionalReference string `json:"transactional_reference,omitempty"` // The reference from the transaction. i.e mpesa reference It is null for eft transactions
}
// type Event struct {
// Type string `json:"type,omitempty"` // The type of transaction
// Resource Resource `json:"resource,omitempty"` // The resource corresponding to the event.
// }
// Resource struct
type Resource struct {
ID string `json:"id,omitempty"` // The api reference of the transaction
Amount float64 `json:"amount,omitempty"` // The amount of the transaction
Status string `json:"status,omitempty"` // The status of the transaction
System string `json:"system,omitempty"` // The mobile money system
Currency string `json:"currency,omitempty"` // Currency
Reference string `json:"reference,omitempty"` // The mpesa reference
TransactionalReference string `json:"transactional_reference,omitempty"`
TillNumber string `json:"till_number,omitempty"` // The till number to which the payment was made
SendingTill string `json:"sending_till,omitempty"` // The till number of the sender
AccountName string `json:"account_name,omitempty"`
AccountNumber string `json:"account_number,omitempty"`
BankBranchReference string `json:"bank_branch_ref,omitempty"`
SettlementMethod string `json:"settlement_method,omitempty"`
SendingMerchant string `json:"sending_merchant,omitempty"` // Name of merchant
SenderPhoneNumber string `json:"sender_phone_number,omitempty"` // The phone number that sent the payment
OriginationTime string `json:"origination_time,omitempty"` // The transaction timestamp
SenderLastName string `json:"sender_last_name,omitempty"` // Last name of payer
SenderFirstName string `json:"sender_first_name,omitempty"` // First name of payer
SenderMiddleName string `json:"sender_middle_name,omitempty"` // Middle name of payer
Destination Destination `json:"destination,omitempty"` // The destination of the settlement transfer
Disbursements []Disbursements `json:"disbursements,omitempty"` // These are the disbursements in that particular transfer batch
}
// type Links struct {
// Self string `json:"self,omitempty"`
// Resource string `json:"resource,omitempty"`
// Callback string `json:"callback_url,omitempty"`
// }
// Event struct
type Event struct {
Type string `json:"type,omitempty"` // The type of transaction
Resource Resource `json:"resource,omitempty"` // The resource corresponding to the event.
}
// type BuyGoodsTrans struct {
// Topic string `json:"topic,omitempty"` // The ID of the Webhook Event
// ID string `json:"id,omitempty"` // The topic of the webhook.
// CreatedAt string `json:"created_at,omitempty"` // The timestamp of when the webhook event was created.
// Event Event `json:"event,omitempty"`
// Links Links `json:"_links,omitempty"` // A JSON object containing links to the Webhook Event and the corresponding Buygoods Transaction resource
// }
// Links struct
type Links struct {
Self string `json:"self,omitempty"`
Resource string `json:"resource,omitempty"`
Callback string `json:"callback_url,omitempty"`
}
// func (bgt BuyGoodsTrans) Validate() error {
// return nil
// }
// BuyGoodsTrans struct
type BuyGoodsTrans struct {
Topic string `json:"topic,omitempty"` // The ID of the Webhook Event
ID string `json:"id,omitempty"` // The topic of the webhook.
CreatedAt string `json:"created_at,omitempty"` // The timestamp of when the webhook event was created.
Event Event `json:"event,omitempty"`
Links Links `json:"_links,omitempty"` // A JSON object containing links to the Webhook Event and the corresponding Buygoods Transaction resource
}
// type CustomerResource struct {
// LastName string `json:"last_name,omitempty"` // Last name of payer
// FirstName string `json:"first_name,omitempty"` // First name of payer
// MiddleName string `json:"middle_name,omitempty"` // Middle name of payer
// PhoneNumber string `json:"phone_number,omitempty"` // The phone number that sent the payment
// }
// type CustomerEvent struct {
// Type string `json:"type,omitempty"` // The type of record (Mobile Money User)
// Resource CustomerResource `json:"resource,omitempty"` // The resource corresponding to the event.
// }
// Validate returns nil if the struct is valid
func (bgt BuyGoodsTrans) Validate() error {
return nil
}
// type CustomerReq struct {
// Topic string `json:"topic,omitempty"` // The ID of the Webhook Event
// ID string `json:"id,omitempty"` // The topic of the webhook.
// CreatedAt string `json:"created_at,omitempty"` // The timestamp of when the webhook event was created.
// Event CustomerEvent `json:"event,omitempty"`
// Links Links `json:"_links,omitempty"` // A JSON object containing links to the Webhook Event and the corresponding Buygoods Transaction resource
// }
// CustomerResource struct
type CustomerResource struct {
LastName string `json:"last_name,omitempty"` // Last name of payer
FirstName string `json:"first_name,omitempty"` // First name of payer
MiddleName string `json:"middle_name,omitempty"` // Middle name of payer
PhoneNumber string `json:"phone_number,omitempty"` // The phone number that sent the payment
}
// type Subscriber struct {
// LastName string `json:"last_name,omitempty"` // Last name of the subscriber
// FirstName string `json:"first_name,omitempty"` // First name of the subscriber
// MiddleName string `json:"middle_name,omitempty"` // Middle name of the subscriber
// PhoneNumber string `json:"phone_number,omitempty"` // The phone number of the subscriber from which the payment will be made
// Email string `json:"email,omitempty"` // E-mail address of the subscriber - optional
// }
// CustomerEvent struct
type CustomerEvent struct {
Type string `json:"type,omitempty"` // The type of record (Mobile Money User)
Resource CustomerResource `json:"resource,omitempty"` // The resource corresponding to the event.
}
// type Amount struct {
// Value string `json:"value,omitempty"` // The amount of the transaction
// Currency string `json:"currency,omitempty"` // Currency
// }
// type ReceiveMpesaReq struct {
// PaymentChannel string `json:"payment_channel,omitempty"` // The payment channel to be used eg. M-PESA
// TillNumber string `json:"till_number,omitempty"` // The online payments till number from the Kopo Kopo dashboard to which the payment will be made
// Subscriber Subscriber `json:"subscriber,omitempty"` // A Subscriber JSON object see below
// Amount Amount `json:"amount,omitempty"` // An Amount JSON object containing currency and amount
// Metadata map[string]interface{} `json:"metadata,omitempty"` // An optional JSON object containing a maximum of 5 key value pairs
// Links Links `json:"_links,omitempty"` // A JOSN object containing the call back URL where the result of the Incoming Payment will be posted
// }
// CustomerReq struct
type CustomerReq struct {
Topic string `json:"topic,omitempty"` // The ID of the Webhook Event
ID string `json:"id,omitempty"` // The topic of the webhook.
CreatedAt string `json:"created_at,omitempty"` // The timestamp of when the webhook event was created.
Event CustomerEvent `json:"event,omitempty"`
Links Links `json:"_links,omitempty"` // A JSON object containing links to the Webhook Event and the corresponding Buygoods Transaction resource
}
// Subscriber struct
type Subscriber struct {
LastName string `json:"last_name,omitempty"` // Last name of the subscriber
FirstName string `json:"first_name,omitempty"` // First name of the subscriber
MiddleName string `json:"middle_name,omitempty"` // Middle name of the subscriber
PhoneNumber string `json:"phone_number,omitempty"` // The phone number of the subscriber from which the payment will be made
Email string `json:"email,omitempty"` // E-mail address of the subscriber - optional
}
// Amount struct
type Amount struct {
Value string `json:"value,omitempty"` // The amount of the transaction
Currency string `json:"currency,omitempty"` // Currency
}
// ReceiveMpesaReq struct
type ReceiveMpesaReq struct {
PaymentChannel string `json:"payment_channel,omitempty"` // The payment channel to be used eg. M-PESA
TillNumber string `json:"till_number,omitempty"` // The online payments till number from the Kopo Kopo dashboard to which the payment will be made
Subscriber Subscriber `json:"subscriber,omitempty"` // A Subscriber JSON object see below
Amount Amount `json:"amount,omitempty"` // An Amount JSON object containing currency and amount
Metadata map[string]interface{} `json:"metadata,omitempty"` // An optional JSON object containing a maximum of 5 key value pairs
Links Links `json:"_links,omitempty"` // A JOSN object containing the call back URL where the result of the Incoming Payment will be posted
}
// Validate returns nil if the struct is valid
func (rmr ReceiveMpesaReq) Validate() error {
return nil
}
// IncomingPaymentEvent struct
type IncomingPaymentEvent struct {
Type string `json:"type,omitempty"` // The ID of the Webhook Event
ID string `json:"id,omitempty"` // The topic of the webhook.
Attributes Attribute `json:"attributes,omitempty"`
}
// Attribute struct
type Attribute struct {
InitiationTime string `json:"initiation_time,omitempty"` // The timestamp of when the webhook event was created.
Status string `json:"status,omitempty"` // A status string denoting the status of the Incoming Payment
Resource Resource `json:"resource,omitempty"` // A JSON Object encapsulating the event of the request
Metadata map[string]interface{} `json:"metadata,omitempty"` // An optional JSON object containing a maximum of 5 key value pairs
Links Links `json:"_links,omitempty"` // A JSON object containing links to the Webhook Event and the corresponding Buygoods Transaction resource
}
// type IncomingPaymentEvent struct {
// Type string `json:"type,omitempty"` // The type of record (Mobile Money User)
// Resource Resource `json:"resource,omitempty"` // The resource corresponding to the event.
// Errors string `json:"errors,omitempty"` // A string containing information on the error than occured
// }
// type ProcessIncommingPaymentReq struct {
// Topic string `json:"topic,omitempty"` // The topic of the request.
// ID string `json:"id,omitempty"` // The ID of the Incoming Payment
// InitiationTime string `json:"initiation_time,omitempty"` // The timestamp of when the webhook event was created.
// Status string `json:"status,omitempty"` // A status string denoting the status of the Incoming Payment
// Event IncomingPaymentEvent `json:"event,omitempty"` // A JSON Object encapsulating the event of the request
// Metadata map[string]interface{} `json:"metadata,omitempty"` // An optional JSON object containing a maximum of 5 key value pairs
// Links Links `json:"_links,omitempty"` // A JSON object containing links to the Webhook Event and the corresponding Buygoods Transaction resource
// }
// ProcessIncommingPaymentReq struct
type ProcessIncommingPaymentReq struct {
Topic string `json:"topic,omitempty"` // The topic of the request.
ID string `json:"id,omitempty"` // The ID of the Incoming Payment
InitiationTime string `json:"initiation_time,omitempty"` // The timestamp of when the webhook event was created.
Status string `json:"status,omitempty"` // A status string denoting the status of the Incoming Payment
Event IncomingPaymentEvent `json:"event,omitempty"` // A JSON Object encapsulating the event of the request
Metadata map[string]interface{} `json:"metadata,omitempty"` // An optional JSON object containing a maximum of 5 key value pairs
Links Links `json:"_links,omitempty"` // A JSON object containing links to the Webhook Event and the corresponding Buygoods Transaction resource
}
// type PaymentRecipient struct {
// LastName string `json:"last_name,omitempty"` // Last name of the recipient
+161 -31
View File
@@ -1,40 +1,170 @@
// Package kopokopo Webhooks are a means of getting notified of events in the Kopo Kopo application.
// To receive webhooks, you need to create a webhook subscription.
package kopokopo
// func (sdk kSDK) CreateWebhook(webookReq CreateWebhookReq) (string, error) {
// panic("Not implemented")
// }
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
)
// // Before processing webhook events, make sure that they originated from Kopo Kopo
// func (sdk kSDK) ValidateWebhook() error {
// panic("Not implemented")
// }
var webhookSubsEndpoint = "api/v1/webhook_subscriptions"
// // Notifies your application when a Buygoods Transaction has been received.
// func (sdk kSDK) C2BSubscription(buyGoodsReq BuyGoodsTrans) (string, error) {
// panic("Not implemented")
// }
func (sdk kSDK) CreateWebhook(token string, webookReq CreateWebhookReq) (string, error) {
if err := webookReq.Validate(); err != nil {
return "", err
}
endpoint := fmt.Sprintf("%s/%s", sdk.baseURL, webhookSubsEndpoint)
req, err := http.NewRequest(http.MethodPost, endpoint, nil)
if err != nil {
return "", err
}
url, err := sdk.getHeaderParams(req, token)
if err != nil {
return "", err
}
id := strings.TrimPrefix(url, fmt.Sprintf("%s/%s/", sdk.baseURL, webhookSubsEndpoint))
return id, nil
}
// // Notifies your application when a B2b (External Till to Till transaction) has been received.
// // These are payments recieved from other tills and not subscribers.
// func (sdk kSDK) B2BSubscription(b2bReq BuyGoodsTrans) (string, error) {
// panic("Not implemented")
// }
func (sdk kSDK) ValidateWebhook(webhookURL string) (BuyGoodsTrans, error) {
if webhookURL == "" {
return BuyGoodsTrans{}, errors.New("empty webhook url")
}
req, err := http.NewRequest(http.MethodPost, webhookURL, nil)
if err != nil {
return BuyGoodsTrans{}, err
}
req.Header.Add("X-KopoKopo-Signature", sdk.credentials.APIKey)
resp, err := sdk.getBodyParams(req, "")
if err != nil {
return BuyGoodsTrans{}, err
}
var bgt BuyGoodsTrans
if err := json.Unmarshal(resp, &bgt); err != nil {
return BuyGoodsTrans{}, err
}
return bgt, nil
}
// // Notifies your application when another Kopo Kopo merchant transfers funds to your Kopo Kopo merchant account (Merchant to Merchant)
// func (sdk kSDK) M2MSubscription(m2mReq BuyGoodsTrans) (string, error) {
// panic("Not implemented")
// }
func (sdk kSDK) C2BSubscription(webhookURL string) (BuyGoodsTrans, error) {
if webhookURL == "" {
return BuyGoodsTrans{}, errors.New("empty webhook url")
}
req, err := http.NewRequest(http.MethodPost, webhookURL, nil)
if err != nil {
return BuyGoodsTrans{}, err
}
req.Header.Add("X-KopoKopo-Signature", sdk.credentials.APIKey)
resp, err := sdk.getBodyParams(req, "")
if err != nil {
return BuyGoodsTrans{}, err
}
var bgt BuyGoodsTrans
if err := json.Unmarshal(resp, &bgt); err != nil {
return BuyGoodsTrans{}, err
}
return bgt, nil
}
// // Notifies your application when a Buygoods Transaction has been reversed
// func (sdk kSDK) C2BReversalSubscription(c2bReq BuyGoodsTrans) error {
// panic("Not implemented")
// }
func (sdk kSDK) B2BSubscription(webhookURL string) (BuyGoodsTrans, error) {
if webhookURL == "" {
return BuyGoodsTrans{}, errors.New("empty webhook url")
}
req, err := http.NewRequest(http.MethodPost, webhookURL, nil)
if err != nil {
return BuyGoodsTrans{}, err
}
req.Header.Add("X-KopoKopo-Signature", sdk.credentials.APIKey)
resp, err := sdk.getBodyParams(req, "")
if err != nil {
return BuyGoodsTrans{}, err
}
var bgt BuyGoodsTrans
if err := json.Unmarshal(resp, &bgt); err != nil {
return BuyGoodsTrans{}, err
}
return bgt, nil
}
// // Parameters contained in a settlement_transfer_completed webhook
// func (sdk kSDK) SettlementSub(setReq BuyGoodsTrans) error {
// panic("Not implemented")
// }
func (sdk kSDK) M2MSubscription(webhookURL string) (BuyGoodsTrans, error) {
if webhookURL == "" {
return BuyGoodsTrans{}, errors.New("empty webhook url")
}
req, err := http.NewRequest(http.MethodPost, webhookURL, nil)
if err != nil {
return BuyGoodsTrans{}, err
}
req.Header.Add("X-KopoKopo-Signature", sdk.credentials.APIKey)
resp, err := sdk.getBodyParams(req, "")
if err != nil {
return BuyGoodsTrans{}, err
}
var bgt BuyGoodsTrans
if err := json.Unmarshal(resp, &bgt); err != nil {
return BuyGoodsTrans{}, err
}
return bgt, nil
}
// func (sdk kSDK) CusomerCreationSub(cReq CustomerReq) error {
// panic("Not implemented")
// }
func (sdk kSDK) C2BReversalSubscription(webhookURL string) (BuyGoodsTrans, error) {
if webhookURL == "" {
return BuyGoodsTrans{}, errors.New("empty webhook url")
}
req, err := http.NewRequest(http.MethodPost, webhookURL, nil)
if err != nil {
return BuyGoodsTrans{}, err
}
req.Header.Add("X-KopoKopo-Signature", sdk.credentials.APIKey)
resp, err := sdk.getBodyParams(req, "")
if err != nil {
return BuyGoodsTrans{}, err
}
var bgt BuyGoodsTrans
if err := json.Unmarshal(resp, &bgt); err != nil {
return BuyGoodsTrans{}, err
}
return bgt, nil
}
func (sdk kSDK) SettlementSub(webhookURL string) (BuyGoodsTrans, error) {
if webhookURL == "" {
return BuyGoodsTrans{}, errors.New("empty webhook url")
}
req, err := http.NewRequest(http.MethodPost, webhookURL, nil)
if err != nil {
return BuyGoodsTrans{}, err
}
req.Header.Add("X-KopoKopo-Signature", sdk.credentials.APIKey)
resp, err := sdk.getBodyParams(req, "")
if err != nil {
return BuyGoodsTrans{}, err
}
var bgt BuyGoodsTrans
if err := json.Unmarshal(resp, &bgt); err != nil {
return BuyGoodsTrans{}, err
}
return bgt, nil
}
func (sdk kSDK) CusomerCreationSub(webhookURL string) (CustomerReq, error) {
if webhookURL == "" {
return CustomerReq{}, errors.New("empty webhook url")
}
req, err := http.NewRequest(http.MethodPost, webhookURL, nil)
if err != nil {
return CustomerReq{}, err
}
req.Header.Add("X-KopoKopo-Signature", sdk.credentials.APIKey)
resp, err := sdk.getBodyParams(req, "")
if err != nil {
return CustomerReq{}, err
}
var cr CustomerReq
if err := json.Unmarshal(resp, &cr); err != nil {
return CustomerReq{}, err
}
return cr, nil
}