paytree 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -1
- data/README.md +99 -3
- data/lib/paytree/configs/mpesa.rb +2 -1
- data/lib/paytree/mpesa/adapters/daraja/b2b.rb +4 -2
- data/lib/paytree/mpesa/adapters/daraja/b2c.rb +10 -3
- data/lib/paytree/mpesa/adapters/daraja/base.rb +5 -0
- data/lib/paytree/utils/error_handling.rb +6 -2
- data/lib/paytree/version.rb +1 -1
- data/lib/paytree.rb +2 -1
- data/paytree.gemspec +1 -1
- metadata +2 -3
- data/paytree-0.2.0.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db5f3b07684338b0a9b63dabf3cc2a00d01adbfcb0c5e8511dd734fc3071d0e7
|
4
|
+
data.tar.gz: aa49b4d56b4eba825fa81ef7a5ff9c75708b92b6036ee5e6439fc1b0821a5e15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d56d06d79d80c8a26569cc9c51b3b55eee3b3ec376e69f40ea21a6e37e325e57a2877cf344be727a98b79614b594ca33feffbadc2591e37f3a5f3d3d5d1d788e
|
7
|
+
data.tar.gz: d8dade7c6661f6ef505c5b25dbbacbbc744610f2333f9ba8d433bcbc01beea82b694abc7727c9c7a8ecf2d1eccd81e5c69caad380930fc162d3c49ad8f6730b0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -18,6 +18,8 @@ Currently supports Kenya's M-Pesa via the Daraja API with plans for additional p
|
|
18
18
|
- **Convention over Configuration**: One clear setup pattern, opinionated defaults
|
19
19
|
- **Safe Defaults**: Sandbox mode, proper timeouts, comprehensive error handling
|
20
20
|
- **Batteries Included**: STK Push, B2C, B2B, C2B operations out of the box
|
21
|
+
- **API Versioning**: Support for both Daraja API v1 and v3 with backward compatibility
|
22
|
+
- **Enhanced Reliability**: Automatic token retry with exponential backoff
|
21
23
|
- **Security First**: Credential management, no hardcoded secrets
|
22
24
|
|
23
25
|
## Quick Start
|
@@ -89,12 +91,59 @@ Paytree.configure_mpesa(
|
|
89
91
|
# shortcode: "YOUR_PRODUCTION_SHORTCODE",
|
90
92
|
# passkey: Rails.application.credentials.mpesa[:passkey],
|
91
93
|
# sandbox: false,
|
92
|
-
#
|
94
|
+
# api_version: "v1", # Optional: "v1" (default) or "v3"
|
95
|
+
# retryable_errors: ["429.001.01", "500.001.02", "503.001.01"] # Optional: errors to retry
|
93
96
|
# )
|
94
97
|
```
|
95
98
|
|
96
99
|
---
|
97
100
|
|
101
|
+
## API Version Support
|
102
|
+
|
103
|
+
Paytree supports both M-Pesa Daraja API v1 and v3 endpoints. The API version can be configured globally or via environment variables.
|
104
|
+
|
105
|
+
### Configuration Options
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
# Use v1 API (default - backward compatible)
|
109
|
+
Paytree.configure_mpesa(
|
110
|
+
key: "YOUR_KEY",
|
111
|
+
secret: "YOUR_SECRET",
|
112
|
+
api_version: "v1" # Default
|
113
|
+
)
|
114
|
+
|
115
|
+
# Use v3 API (latest features)
|
116
|
+
Paytree.configure_mpesa(
|
117
|
+
key: "YOUR_KEY",
|
118
|
+
secret: "YOUR_SECRET",
|
119
|
+
api_version: "v3"
|
120
|
+
)
|
121
|
+
|
122
|
+
# Or via environment variable
|
123
|
+
ENV['MPESA_API_VERSION'] = 'v3'
|
124
|
+
Paytree.configure_mpesa(
|
125
|
+
key: "YOUR_KEY",
|
126
|
+
secret: "YOUR_SECRET"
|
127
|
+
# api_version automatically picked up from ENV
|
128
|
+
)
|
129
|
+
```
|
130
|
+
|
131
|
+
### Differences Between v1 and v3
|
132
|
+
|
133
|
+
| Feature | v1 | v3 |
|
134
|
+
|---------|----|----|
|
135
|
+
| **Endpoints** | `/mpesa/b2c/v1/paymentrequest` | `/mpesa/b2c/v3/paymentrequest` |
|
136
|
+
| **OriginatorConversationID** | Not required | Auto-generated UUID |
|
137
|
+
| **Reliability** | Standard | Enhanced with better tracking |
|
138
|
+
|
139
|
+
|
140
|
+
**Backward Compatibility:**
|
141
|
+
- Existing code continues to work unchanged (defaults to v1)
|
142
|
+
- No breaking changes when upgrading Paytree versions
|
143
|
+
- Can switch between v1/v3 by changing configuration only
|
144
|
+
|
145
|
+
---
|
146
|
+
|
98
147
|
## Usage Examples
|
99
148
|
|
100
149
|
### STK Push (Customer Payment)
|
@@ -168,7 +217,7 @@ end
|
|
168
217
|
|
169
218
|
Send funds directly to a customer’s M-Pesa wallet via the B2C API.
|
170
219
|
|
171
|
-
### Example
|
220
|
+
### Basic Example
|
172
221
|
```ruby
|
173
222
|
response = Paytree::Mpesa::B2C.call(
|
174
223
|
phone_number: "254712345678",
|
@@ -186,6 +235,43 @@ else
|
|
186
235
|
end
|
187
236
|
```
|
188
237
|
|
238
|
+
### v3 API Features
|
239
|
+
|
240
|
+
When using `api_version: "v3"`, B2C calls automatically include an `OriginatorConversationID` for enhanced tracking:
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
# Configure for v3 API
|
244
|
+
Paytree.configure_mpesa(
|
245
|
+
key: "YOUR_KEY",
|
246
|
+
secret: "YOUR_SECRET",
|
247
|
+
api_version: "v3"
|
248
|
+
)
|
249
|
+
|
250
|
+
# Same call, but now uses v3 endpoint with auto-generated OriginatorConversationID
|
251
|
+
response = Paytree::Mpesa::B2C.call(
|
252
|
+
phone_number: "254712345678",
|
253
|
+
amount: 100
|
254
|
+
)
|
255
|
+
|
256
|
+
# v3 response includes additional tracking data
|
257
|
+
if response.success?
|
258
|
+
puts "Conversation ID: #{response.data["ConversationID"]}"
|
259
|
+
puts "Originator ID: #{response.data["OriginatorConversationID"]}" # Auto-generated UUID
|
260
|
+
end
|
261
|
+
```
|
262
|
+
|
263
|
+
### Custom OriginatorConversationID (v3 only)
|
264
|
+
|
265
|
+
You can provide your own tracking ID for v3 API calls:
|
266
|
+
|
267
|
+
```ruby
|
268
|
+
response = Paytree::Mpesa::B2C.call(
|
269
|
+
phone_number: "254712345678",
|
270
|
+
amount: 100,
|
271
|
+
originator_conversation_id: "CUSTOM-TRACK-#{Time.now.to_i}"
|
272
|
+
)
|
273
|
+
```
|
274
|
+
|
189
275
|
---
|
190
276
|
|
191
277
|
## C2B (Customer to Business)
|
@@ -321,6 +407,9 @@ Paytree allows you to configure which error codes should be considered retryable
|
|
321
407
|
- `"429.001.01"` - Rate limit exceeded
|
322
408
|
- `"500.001.02"` - Temporary server error
|
323
409
|
- `"503.001.01"` - Service temporarily unavailable
|
410
|
+
- `"timeout.connection"` - Network connection timeout (Net::OpenTimeout)
|
411
|
+
- `"timeout.read"` - Network read timeout (Net::ReadTimeout)
|
412
|
+
- `"timeout.request"` - HTTP request timeout (Faraday::TimeoutError)
|
324
413
|
|
325
414
|
Configure retryable errors during setup:
|
326
415
|
|
@@ -328,7 +417,14 @@ Configure retryable errors during setup:
|
|
328
417
|
Paytree.configure_mpesa(
|
329
418
|
key: "YOUR_KEY",
|
330
419
|
secret: "YOUR_SECRET",
|
331
|
-
retryable_errors: [
|
420
|
+
retryable_errors: [
|
421
|
+
"429.001.01", # Rate limit
|
422
|
+
"500.001.02", # Server error
|
423
|
+
"503.001.01", # Service unavailable
|
424
|
+
"timeout.connection", # Connection timeout
|
425
|
+
"timeout.read", # Read timeout
|
426
|
+
"timeout.request" # Request timeout
|
427
|
+
]
|
332
428
|
)
|
333
429
|
```
|
334
430
|
|
@@ -5,7 +5,7 @@ module Paytree
|
|
5
5
|
class Mpesa
|
6
6
|
attr_accessor :key, :secret, :shortcode, :passkey, :adapter,
|
7
7
|
:initiator_name, :initiator_password, :sandbox,
|
8
|
-
:extras, :timeout, :retryable_errors
|
8
|
+
:extras, :timeout, :retryable_errors, :api_version
|
9
9
|
|
10
10
|
def initialize
|
11
11
|
@extras = {}
|
@@ -13,6 +13,7 @@ module Paytree
|
|
13
13
|
@mutex = Mutex.new
|
14
14
|
@timeout = 30 # Default 30 second timeout
|
15
15
|
@retryable_errors = [] # Default empty array
|
16
|
+
@api_version = "v1" # Default to v1 for backward compatibility
|
16
17
|
end
|
17
18
|
|
18
19
|
def base_url
|
@@ -5,7 +5,9 @@ module Paytree
|
|
5
5
|
module Adapters
|
6
6
|
module Daraja
|
7
7
|
class B2B < Base
|
8
|
-
|
8
|
+
def self.endpoint
|
9
|
+
"/mpesa/b2b/#{config.api_version}/paymentrequest"
|
10
|
+
end
|
9
11
|
|
10
12
|
class << self
|
11
13
|
def call(short_code:, receiver_shortcode:, amount:, account_reference:, **opts)
|
@@ -28,7 +30,7 @@ module Paytree
|
|
28
30
|
ResultURL: config.extras[:result_url]
|
29
31
|
}.compact
|
30
32
|
|
31
|
-
post_to_mpesa(:b2b,
|
33
|
+
post_to_mpesa(:b2b, endpoint, payload)
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
@@ -5,7 +5,9 @@ module Paytree
|
|
5
5
|
module Adapters
|
6
6
|
module Daraja
|
7
7
|
class B2C < Base
|
8
|
-
|
8
|
+
def self.endpoint
|
9
|
+
"/mpesa/b2c/#{config.api_version}/paymentrequest"
|
10
|
+
end
|
9
11
|
|
10
12
|
class << self
|
11
13
|
def call(phone_number:, amount:, **opts)
|
@@ -23,9 +25,14 @@ module Paytree
|
|
23
25
|
CommandID: opts[:command_id] || "BusinessPayment",
|
24
26
|
Remarks: opts[:remarks] || "OK",
|
25
27
|
Occasion: opts[:occasion] || "Payment"
|
26
|
-
}
|
28
|
+
}
|
29
|
+
|
30
|
+
# Add OriginatorConversationID for v3
|
31
|
+
if config.api_version == "v3"
|
32
|
+
payload[:OriginatorConversationID] = opts[:originator_conversation_id] || generate_conversation_id
|
33
|
+
end
|
27
34
|
|
28
|
-
post_to_mpesa(:b2c,
|
35
|
+
post_to_mpesa(:b2c, endpoint, payload.compact)
|
29
36
|
end
|
30
37
|
end
|
31
38
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "base64"
|
2
|
+
require "securerandom"
|
2
3
|
require_relative "response_helpers"
|
3
4
|
require_relative "../../../utils/error_handling"
|
4
5
|
|
@@ -106,6 +107,10 @@ module Paytree
|
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|
110
|
+
def generate_conversation_id
|
111
|
+
SecureRandom.uuid
|
112
|
+
end
|
113
|
+
|
109
114
|
private
|
110
115
|
|
111
116
|
def fetch_token
|
@@ -7,7 +7,7 @@ module Paytree
|
|
7
7
|
Paytree::Errors::Base => e
|
8
8
|
emit_error(e, context)
|
9
9
|
raise
|
10
|
-
rescue Faraday::TimeoutError => e
|
10
|
+
rescue Faraday::TimeoutError, Net::OpenTimeout, Net::ReadTimeout => e
|
11
11
|
handle_faraday_error(
|
12
12
|
e,
|
13
13
|
context,
|
@@ -54,7 +54,11 @@ module Paytree
|
|
54
54
|
code = info[:code]
|
55
55
|
else
|
56
56
|
message = error.message
|
57
|
-
code =
|
57
|
+
code = case error
|
58
|
+
when Net::OpenTimeout then "timeout.connection"
|
59
|
+
when Net::ReadTimeout then "timeout.read"
|
60
|
+
when Faraday::TimeoutError then "timeout.request"
|
61
|
+
end
|
58
62
|
end
|
59
63
|
|
60
64
|
wrap_and_raise(
|
data/lib/paytree/version.rb
CHANGED
data/lib/paytree.rb
CHANGED
data/paytree.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
|
28
28
|
spec.files = Dir.chdir(__dir__) do
|
29
29
|
`git ls-files -z`.split("\x0").reject do |f|
|
30
|
-
f.match(%r{^(test|spec|features|bin|exe)/}) || f.include?(".git")
|
30
|
+
f.match(%r{^(test|spec|features|bin|exe)/}) || f.include?(".git") || f.end_with?(".gem")
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paytree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Chuck
|
@@ -123,7 +123,6 @@ files:
|
|
123
123
|
- lib/paytree/response.rb
|
124
124
|
- lib/paytree/utils/error_handling.rb
|
125
125
|
- lib/paytree/version.rb
|
126
|
-
- paytree-0.2.0.gem
|
127
126
|
- paytree.gemspec
|
128
127
|
- sig/paytree.rbs
|
129
128
|
homepage: https://github.com/mundanecodes/paytree
|
@@ -154,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
153
|
- !ruby/object:Gem::Version
|
155
154
|
version: '0'
|
156
155
|
requirements: []
|
157
|
-
rubygems_version: 3.6.
|
156
|
+
rubygems_version: 3.6.7
|
158
157
|
specification_version: 4
|
159
158
|
summary: A Ruby wrapper for the Mpesa API in Kenya.
|
160
159
|
test_files: []
|
data/paytree-0.2.0.gem
DELETED
Binary file
|