K2ConnectRuby For Rails
Ruby SDK for connection to the Kopo Kopo API. This documentation gives you the specifications for connecting your systems to the Kopo Kopo Application. Primarily, the library provides functionality to do the following:
- Receive Webhook notifications.
- Receive payments from your users/customers.
- Initiate reversals for payments from your users/customers
- Initiate payments to third parties.
- Initiate transfers to your preferred accounts.
- Create payment links
The library is optimized for Rails Based Frameworks. Please note, all requests MUST be made over HTTPS. Any non-secure requests are met with a redirect (HTTP 302) to the HTTPS equivalent URI. All calls made without authentication will also fail.
LINKS
Installation
Add this line to your application's Gemfile:
gem 'k2-connect-ruby'
And then execute:
$ bundle install
Or install it yourself:
$ gem install k2-connect-ruby
Usage
Add the require line to use the gem:
require 'k2-connect-ruby'
To set the base_url:
K2ConnectRuby::K2Utilities::Config::K2Config.base_url = "https://sandbox.kopokopo.com/"
[!NOTE] The API version in use is K2 Connect v2. To use K2 Connect v2, make use of versions 3.0.0 of the SDK.
[!WARNING] The following APIs are deprecated on version 2 (v2).
- Pay (Replaced with Send money)
- Transfers (Replaced with Send money)
- SMS Notifications
Authorization
Ensure you first Register your application with the Kopo Kopo Sandbox.
Once an application is registered you will obtain your client_id and client_secret (aka client credentials), which will be used to identify your application when calling the Kopo Kopo API.
For more Information, visit our API docs.
In order to request for application authorization and receive an access token, we need to execute the client credentials flow, this is done so by having your application server make a HTTPS request to the Kopo Kopo authorization server, through the K2AccessToken class.
access_token = K2ConnectRuby::K2Entity::K2Token.new('your_client_id', 'your_client_secret').request_token
Webhook Subscription
Remember to store highly sensitive information like the client credentials, in a config file, while indicating in your .gitignore file.
Next, we formally create the webhook subscription by calling on the webhook_subscribe method. Ensure the following arguments are passed:
- event type
REQUIRED - url
REQUIRED - scope
REQUIRED: istillif event_type is a buygoods_transaction_received, buygoods_transaction_reversed, b2b_transaction_received, card_transaction_received, card_transaction_voided or card_transaction_reversed andcompanyif not - scope_reference: is
REQUIREDif scope is till - enable_daraja_payload:
OPTIONAL. By default, it is set tofalse
Supported event types:
- buygoods_transaction_received
- buygoods_transaction_reversed
- b2b_transaction_received
- b2b_transaction_reversed
- card_transaction_received
- card_transaction_voided
- card_transaction_reversed
- customer_created
- settlement_transfer_completed
Code example;
require 'k2-connect-ruby'
access_token = K2ConnectRuby::K2Entity::K2Token.new('your_client_id', 'your_client_secret').request_token
k2subscriber = K2ConnectRuby::K2Entity::K2Subscribe.new(access_token)
your_request = {
event_type: 'buygoods_transaction_received',
url: callback_url,
scope: 'till',
scope_reference: '112233',
enable_daraja_payload: true
}
k2subscriber.webhook_subscribe(your_request)
STK-Push
Receive Payments
To receive payments from M-PESA users via STK Push we first create a K2Stk Object, passing the access_token that was created prior.
k2_stk = K2ConnectRuby::K2Entity::K2Stk.new(access_token)
Afterwards we send a POST request for receiving Payments by calling the following method and passing the params value received from the POST Form Request:
k2_stk.send_stk_request(your_input)
Ensure the following arguments are passed:
- payment_channel
REQUIRED - till_number
REQUIRED: from the Online Payments Account created with Kopo Kopo Inc Web App - first_name
- last_name
- phone_number
REQUIRED - currency:
KESexpected - value
REQUIRED - callback_url
REQUIRED
A Successful Response will be received containing the URL of the Payment Location.
Query Request Status
To Query the STK Payment Request Status pass the Payment location URL response that is returned:
k2_stk.query_resource(k2_stk.location_url)
To Query the most recent STK Request Status is as follows:
k2_stk.query_status
As a result a JSON payload will be returned, accessible with the k2_response_body variable.
Code example;
k2_stk = K2ConnectRuby::K2Entity::K2Stk.new(access_token)
your_request = {
payment_channel: "M-PESA STK Push",
till_number: "K112233",
first_name: "First",
middle_name: "Middle",
last_name: "Last",
phone_number: "phone_number",
email: "test_email@email.com",
currency: "KES",
amount: "100",
metadata: {
customer_id: "123_456_789",
reference: "123_456",
notes: "Placeholder text",
},
callback_url: callback_url,
}
k2_stk.send_stk_request(your_request)
k2_stk.query_resource(k2_stk.location_url)
Add External Recipients
First Create the ExternalRecipient Object passing the access token
external_recipient = K2ConnectRuby::K2Entity::ExternalRecipient.new(access_token)
Add a external recipient, with the following arguments:
Mobile External Recipient
- type: 'mobile_wallet'
REQUIRED - first_name
REQUIRED - last_name
REQUIRED - phone_number
REQUIRED - email
REQUIRED - network
REQUIRED
Bank External Recipient
- type: 'bank_account'
REQUIRED - account_name
REQUIRED - account_number
REQUIRED - bank_branch_ref
REQUIRED
Paybill External Recipient
- type: 'paybill'
REQUIRED - paybill_name
REQUIRED - paybill_number
REQUIRED - paybill_account_number
REQUIRED
Till External Recipient
- type: 'till'
REQUIRED - till_name
REQUIRED - till_number
REQUIRED
external_recipient = K2ConnectRuby::K2Entity::ExternalRecipient.new(access_token)
your_input = {
type: "mobile_wallet",
first_name: "First",
last_name: "Last",
email: "test_email@email.com",
phone_number: "phone_number",
}
external_recipient.add_external_recipient(your_input)
The type value can be mobile_wallet, bank_account, till or paybill
A Successful Response is returned with the URL of the recipient resource.
Query add ExternalRecipient Request Status
To Query the status of the Add Recipient:
external_recipient.query_resource(external_recipient.recipients_location_url)
To Query the most recent status of the Add Recipient:
external_recipient.query_status
A HTTP Response will be returned in a JSON Payload, accessible with the k2_response_body variable.
Code example;
external_recipient = K2ConnectRuby::K2Entity::ExternalRecipient.new(access_token)
external_recipient.add_external_recipient(your_input)
external_recipient.query_resource(external_recipient.recipients_location_url)
Add Transfer Accounts
Add pre-approved transfer accounts, to which one can transfer funds to. Can be either a bank or mobile wallet account, with the following details:
Mobile Transfer Account
- type: 'merchant_wallet'
REQUIRED - first_name
REQUIRED - last_name
REQUIRED - phone_number
REQUIRED - network: 'Safaricom'
REQUIRED - nickname
Bank Transfer Account
- type: 'merchant_bank_account'
REQUIRED - account_name
REQUIRED - account_number
REQUIRED - bank_branch_ref
REQUIRED - settlement_method: 'EFT' or 'RTS'
REQUIRED - nickname
transfer_account = K2ConnectRuby::K2Entity::TransferAccount.new(access_token)
# Add a mobile merchant wallet
merchant_wallet_params = {
type: "merchant_wallet",
first_name: "first_name",
last_name: "last_name",
email: "email@email.com",
phone_number: "phone_number",
nickname: "nickname",
}
transfer_account.add_transfer_account(merchant_wallet_params)
# Add a merchant bank account
merchant_bank_account_params = {
type: "merchant_bank_account",
account_name: Faker::Name.name_with_middle,
account_number: Faker::Number.number(digits: 10),
bank_branch_ref: "reference to bank branch", # View https://developers.kopokopo.com/ on how to retrieve the bank branch reference
settlement_method: "EFT",
nickname: Faker::Name.name_with_middle,
}
transfer_account.add_transfer_account(merchant_bank_account_params)
A Successful Response is returned with the URL of the resource.
Query add transfer account Request Status
To Query the status of the Add Transfer account:
transfer_account.query_resource(transfer_account.transfer_account_location_url)
To Query the most recent status of the Add Transfer account:
transfer_account.query_status
A HTTP Response will be returned in a JSON Payload, accessible with the k2_response_body variable.
Code example;
transfer_account = K2ConnectRuby::K2Entity::TransferAccount.new(access_token)
transfer_account.add_transfer_account(your_input)
transfer_account.query_resource(transfer_account.transfer_account_location_url)
Send money
First Create the SendMoney Object passing the access token
send_money = K2ConnectRuby::K2Entity::SendMoney.new(access_token)
Creating an Outgoing Payment to a third party.
send_money.create_payment(your_input)
The following arguments should be passed within a hash:
- destinations (array of hashes).
REQUIREDunless doing send money sweep of available funds - currency
KESexpected - source_identifier
- callback_url
REQUIRED
The hash structure within the destinations array:
Send to External Mobile Recipient
- type: 'mobile_wallet'
REQUIRED - phone_number
REQUIRED - amount
REQUIRED - description
REQUIRED - network
REQUIRED - first_name
- last_name
- nickname
- favourite
Send to External Bank account Recipient
- type: 'bank_account'
REQUIRED - account_name
REQUIRED - account_number
REQUIRED - amount
REQUIRED - description
REQUIRED - bank_branch_ref
REQUIRED - nickname
- favourite
Send to External Paybill Recipient
- type: 'paybill'
REQUIRED - paybill_number
REQUIRED - paybill_account_number
REQUIRED - paybill_name
- description
REQUIRED - nickname
- favourite
Send to External Till Recipient
- type: 'till'
REQUIRED - till_number
REQUIRED - till_name
- description
REQUIRED - nickname
- favourite
Send to My Mobile Phone
- type: 'merchant_wallet'
REQUIRED - reference
REQUIRED - amount
REQUIRED
Send to My Bank account
- type: 'merchant_bank_account'
REQUIRED - reference
REQUIRED - amount
REQUIRED
A Successful Response is returned with the URL of the Payment resource in the HTTP Location Header.
Query SendMoney Request Status
To Query the status of the Outgoing Payment request:
send_money.query_resource(send_money.payments_location_url)
To Query the most recent status of Outgoing Payment request:
send_money.query_status
A HTTP Response will be returned in a JSON Payload, accessible with the k2_response_body variable.
Code example of send money to an external recipient;
# Send money to external recipient
params = {
destinations: [
{
type: "bank_account",
bank_branch_ref: "reference to bank branch", # View https://developers.kopokopo.com/ on how to retrieve the bank branch reference
account_name: Faker::Name.name,
account_number: "bank account number",
nickname: Faker::Name.name,
amount: "1000",
description: "send money via K2 Connect",
},
],
currency: "KES",
source_identifier: nil,
metadata: {
order_no: "ORD192832",
},
callback_url: Faker::Internet.url,
}
access_token = K2ConnectRuby::K2Entity::K2Token.new("client_id", "client_secret").request_token
send_money = K2ConnectRuby::K2Entity::SendMoney.new(access_token)
send_money.create_payment(params)
Code example of send money to a transfer account;
# Send money to a transfer account
params = {
destinations: [
{
type: "merchant_wallet",
reference: destination_reference, # Retrieved from logging into the merchant app https://app.kopokopo.com
amount: "1000",
},
],
currency: "KES",
source_identifier: nil,
callback_url: callback_url,
}
access_token = K2ConnectRuby::K2Entity::K2Token.new("client_id", "client_secret").request_token
send_money = K2ConnectRuby::K2Entity::SendMoney.new(access_token)
send_money.create_payment(params)
Code example of send money to my accounts (Sweep all available funds);
# Send money to my accounts
params = {
destinations: [],
currency: "KES",
source_identifier: nil,
callback_url: callback_url,
}
access_token = K2ConnectRuby::K2Entity::K2Token.new("client_id", "client_secret").request_token
send_money = K2ConnectRuby::K2Entity::SendMoney.new(access_token)
send_money.create_payment(params)
Polling
Allows you to poll transactions received on the Kopo Kopo system within a certain time range, and either for a company or a specific till.
First Create the K2Polling Object
k2_polling = K2ConnectRuby::K2Entity::K2Polling.new(access_token)
The following details should be passed:
- scope
REQUIRED - scope_reference is
REQUIREDif scope is till - from_time
REQUIRED - to_time
REQUIRED - callback_url
REQUIRED
Sample code example:
your_input = {
scope: "company",
scope_reference: "",
from_time: "2025-04-12T08:50:22+03:00",
to_time: "2025-04-19T08:50:22+03:00",
callback_url: 'http://placeholder_url_com'
}
k2_polling = K2ConnectRuby::K2Entity::K2Polling.new("access_token")
k2_polling.poll(your_input)
k2_polling.location_url # => "https://sandbox.kopokopo.com/api/v1/polling/247b1bd8-f5a0-4b71-a898-f62f67b8ae1c"
Query Request
To Query the status of the prior initiated Polling Request pass the location_url response as shown:
k2_polling.query_resource_url(k2_polling.location_url)
To Query the most recent initiated Polling Request:
k2_polling.query_resource
A HTTP Response will be returned in a JSON Payload, accessible with the k2_response_body variable.
Reversals
Initiate a reversal for a C2B or B2B transaction to your till and get the reversal request's status.
Initiate a reversal
Create an instance of K2ConnectRuby::K2Entity::Reversal object and call initiate_reversal method with the following reversal parameters:
transaction_reference: Reference of the transaction to be reversed.REQUIREDreason: Reason for the reversal.REQUIREDmetadata: A hash with a maximum of 5 key-value pairs.callback_url: URL that the result will be posted to.REQUIRED
reversal_params = {
transaction_reference: "Y7T2990R11",
reason: "Erroneous payment",
metadata: {
order_no: "ORD192832",
},
callback_url: "https://example.com/callback",
}
access_token = K2ConnectRuby::K2Entity::K2Token.new("client_id", "client_secret").request_token
k2_reversal = K2ConnectRuby::K2Entity::Reversal.new(access_token)
k2_reversal.initiate_reversal(reversal_params)
Get status of reversal request
reversal_params = {
transaction_reference: "Y7T2990R11",
reason: "Erroneous payment",
metadata: {
order_no: "ORD192832",
},
callback_url: "https://example.com/callback",
}
access_token = K2ConnectRuby::K2Entity::K2Token.new("client_id", "client_secret").request_token
k2_reversal = K2ConnectRuby::K2Entity::Reversal.new(access_token)
location_url = k2_reversal.initiate_reversal(reversal_params)
# Get status of current reversal request
k2_reversal.query_status
# Get status of specific reversal request
k2_reversal.query_resource(location_url)
Payment Links
Generate a payment link that you can share with a customer to collect a payment
Create a payment link
Create an instance of K2ConnectRuby::K2Entity::PaymentLink object and call create_payment_link method with the following payment link parameters:
till_number: Till number for the M-PESA or Online Payments Account that will receive the payment.REQUIREDcurrency: 3-digit ISO format currency code.REQUIREDamount: The amount the customer will pay.REQUIREDpayment_reference: The merchant internal reference for the payment.note: Note for the customer as they make the payment.metadata: A hash with a maximum of 5 key pairs.callback_url: URL that the payment link result will be posted to once a customer makes a payment.REQUIRED
payment_link_params = {
till_number: "4321",
currency: "KES",
amount: 1000,
payment_reference: "INV02932922",
note: "Payment for monthly internet subscription",
metadata: {
account_number: "1234567",
},
callback_url: "https://example.com/callback",
}
access_token = K2ConnectRuby::K2Entity::K2Token.new("client_id", "client_secret").request_token
k2_payment_links = K2ConnectRuby::K2Entity::PaymentLink.new(access_token)
k2_payment_links.create_payment_link(payment_link_params)
Cancel payment link
payment_link_params = {
till_number: "4321",
currency: "KES",
amount: 1000,
payment_reference: "INV02932922",
note: "Payment for monthly internet subscription",
metadata: {
account_number: "1234567",
},
callback_url: "https://example.com/callback",
}
access_token = K2ConnectRuby::K2Entity::K2Token.new("client_id", "client_secret").request_token
k2_payment_links = K2ConnectRuby::K2Entity::PaymentLink.new(access_token)
location_url = k2_payment_links.create_payment_link(payment_link_params)
# Cancel payment link
k2_payment_links.cancel_payment_link(location_url)
Get status of payment link
payment_link_params = {
till_number: "4321",
currency: "KES",
amount: 1000,
payment_reference: "INV02932922",
note: "Payment for monthly internet subscription",
metadata: {
account_number: "1234567",
},
callback_url: "https://example.com/callback",
}
access_token = K2ConnectRuby::K2Entity::K2Token.new("client_id", "client_secret").request_token
k2_payment_links = K2ConnectRuby::K2Entity::PaymentLink.new(access_token)
location_url = k2_payment_links.create_payment_link(payment_link_params)
# Get status of current payment link
k2_payment_links.query_status
# Get status of specific payment link
k2_payment_links.query_resource(location_url)
Parsing the JSON Payload
The K2Client class will be use to parse the Payload received from Kopo Kopo, and to further consume the webhooks and split the responses into components, the K2Authenticator and K2ProcessResult Classes will be used.
K2Client Object
First Create an Object of the K2Client class to Parse the response, passing the client_secret_key received from Kopo Kopo:
k2_parse = K2ConnectRuby::K2Services::K2Client.new(client_secret)
Parse the request
k2_parse.parse_request(request)
Create an Object
Create an Object to receive the components resulting from processing the parsed request results which will be returned by the following method:
k2_components = K2ConnectRuby::K2Utilities::K2ProcessResult.process(k2_parse.hash_body, API_KEY, k2_parse.k2_signature)
or the parsed webhook results which will be returned by the following method:
k2_components = K2ConnectRuby::K2Utilities::K2ProcessWebhook.process(k2_parse.hash_body, API_KEY, k2_parse.k2_signature)
Code example:
k2_parse = K2ConnectRuby::K2Services::K2Client.new(API_KEY)
k2_parse.parse_request(request)
k2_components = K2ConnectRuby::K2Utilities::K2ProcessResult.process(k2_parse.hash_body, API_KEY, k2_parse.k2_signature)
Below is a list of key symbols accessible for each of the Results retrieved after processing it into an Object.
Buy Goods Transaction Received:
idresource_idtopiccreated_atevent_typereferenceorigination_timesender_phone_numberhashed_sender_phoneamountcurrencytill_numbersystemstatussender_first_namesender_last_namelinks_selflinks_resource
Buy Goods Transaction Reversed:
idresource_idtopiccreated_atevent_typereferenceorigination_timesender_phone_numberamountcurrencytill_numbersystemstatussender_first_namesender_last_namelinks_selflinks_resource
Settlement Transfer:
idresource_idtopiccreated_atevent_typeorigination_timeamountcurrencyresource_statuslinks_selflinks_resourcedestination_referencedestination_typeBank Account Destination Typedestination_account_namedestination_account_numberdestination_bank_branch_refdestination_settlement_methodMerchant Wallet Destination Typedestination_first_namedestination_last_namedestination_phone_numberdestination_network
Customer Created:
idresource_idtopiccreated_atevent_typeresource_first_nameresource_middle_nameresource_last_nameresource_phone_numberlinks_selflinks_resource
B2b Transaction Received (External Till to Till):
idresource_idtopiccreated_atevent_typereferenceorigination_timeamountcurrencytill_numberstatuslinks_selflinks_resourcesending_till
B2B Transaction Reversed:
idresource_idtopiccreated_atevent_typereferenceorigination_timeamountcurrencytill_numberstatuslinks_selflinks_resourcesending_till
Card Transaction Received
idresource_idtopiccreated_ateventreferenceorigination_timeamountcurrencytill_numbercustomer_cc_numberstatuslinks_selflinks_resourcesettled
Card Transaction Reversed:
idresource_idtopiccreated_ateventreferenceorigination_timeamountcurrencytill_numbercustomer_cc_numberstatuslinks_selflinks_resource
Card Transaction Voided:
idresource_idtopiccreated_atevent_typereferenceorigination_timeamountcurrencytill_numbercustomer_cc_numberstatuslinks_selflinks_resource
Process STK Push Payment Request Result
idtypeinitiation_timestatusevent_typeresource_idresource_statustransaction_referenceorigination_timesender_phone_numberamountcurrencytill_numbersystemsender_first_namesender_middle_namesender_last_nameerrorsmetadatalinks_selfcallback_url
Process Send money Result
idtypecreated_atstatustransfer_batchcurrencyvaluemetadatalinks_selfcallback_url
Reversal Result
idtypetransaction_referencestatuscreated_atreasonreversal_bulk_paymenterrorsmetadatacallback_urllinks_self
Payment Link Result
idtypestatuscreated_attill_nametill_numberpayment_referencecurrencyamountnotepayment_linkerrorsmetadatacallback_urllinks_self
If you want to convert the Object into a Hash or Array, the following methods can be used.
Hash:
k2_hash_components = K2ConnectRuby::K2Utilities::K2ProcessResult.return_obj_hash(k2_components)Array:
k2_array_components = K2ConnectRuby::K2Utilities::K2ProcessResult.return_obj_array(k2_components)
Sample Web Application examples written in Rails and Sinatra frameworks that utilize this library are available in the example_app folder or in the following GitHub hyperlinks:
##### Take Note; the Library is optimized for Rails frameworks version 8.
Development
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
Author
Name: David Kariuki Mwangi
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/kopokopo/k2-connect-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
License
The gem is available as open source under the terms of the [MIT License].
Changelog
Code of Conduct
Everyone interacting in the K2ConnectRuby project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.