peyemapi-sdk 1.0.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 +7 -0
- data/README.md +132 -0
- data/lib/peyemapi/client.rb +106 -0
- data/lib/peyemapi/error.rb +14 -0
- data/lib/peyemapi/version.rb +3 -0
- data/lib/peyemapi.rb +13 -0
- metadata +118 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 56fb1e10f7666ec0777dd3e14c150cd3b3a7bec1b18bc1c1b669579afece01f5
|
|
4
|
+
data.tar.gz: fe7cb38ec9250d43008f7ac5b3fc7972ee2698f17fc773da7428204ae30db1ea
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f3d8ade57d0ac3d027c00842425e6e1c674dcf4be61413722716254fe4eaf86e7ad07d794726834fc33af9578c8730b1cbf4d4b3011aa57eae2bd3cd3c5fa561
|
|
7
|
+
data.tar.gz: f2e4b39b774cb99b75c8f6fc7ae52336bf9e509dfb00c263fa1a1a0c24dd3a3e81fc92151371af8588381954c14be8eed726ec64308dc8ac94e4d2bf05d90f27
|
data/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# PeyemAPI Ruby SDK
|
|
2
|
+
|
|
3
|
+
A gem for integrating [PeyemAPI](https://peyem.app) payments into any Ruby application — works with **Rails**, **Sinatra**, **Hanami**, and plain Ruby scripts.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add to your `Gemfile`:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "peyemapi-sdk"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then run:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bundle install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or install globally:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
gem install peyemapi-sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### Initialize the client
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
require "peyemapi"
|
|
31
|
+
|
|
32
|
+
# Reads PEYEM_API_KEY from environment
|
|
33
|
+
client = Peyemapi::Client.new
|
|
34
|
+
|
|
35
|
+
# Or pass key directly
|
|
36
|
+
client = Peyemapi::Client.new("sk_user_...")
|
|
37
|
+
|
|
38
|
+
# Shorthand
|
|
39
|
+
client = Peyemapi.client("sk_user_...")
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Create a Payment
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
response = client.create_payment(
|
|
46
|
+
amount: 500, # HTG
|
|
47
|
+
reference_id: "ORDER-123",
|
|
48
|
+
return_url: "https://example.com/return",
|
|
49
|
+
description: "Optional description"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if response["payment_url"]
|
|
53
|
+
redirect_to response["payment_url"] # Rails example
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Check Payment Status
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
status = client.check_status("ORDER-123")
|
|
61
|
+
puts status["status"] # "completed", "pending", etc.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Get Account Balance
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
balance = client.get_balance
|
|
68
|
+
puts "#{balance["balance"]} #{balance["currency"]}" # "12500 HTG"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Webhook Verification
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
# Rails example
|
|
75
|
+
class WebhooksController < ApplicationController
|
|
76
|
+
skip_before_action :verify_authenticity_token
|
|
77
|
+
|
|
78
|
+
def payment
|
|
79
|
+
payload = request.raw_post
|
|
80
|
+
signature = request.headers["X-Webhook-Signature"]
|
|
81
|
+
secret = ENV["PEYEM_WEBHOOK_SECRET"]
|
|
82
|
+
|
|
83
|
+
unless Peyemapi::Client.verify_webhook(payload, signature, secret)
|
|
84
|
+
return head :unauthorized
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
data = JSON.parse(payload)
|
|
88
|
+
# handle event...
|
|
89
|
+
head :ok
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Environment Variables
|
|
95
|
+
|
|
96
|
+
| Variable | Description |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `PEYEM_API_KEY` | Your secret API key |
|
|
99
|
+
| `PEYEM_API_URL` | Override the API base URL (optional) |
|
|
100
|
+
| `PEYEM_WEBHOOK_SECRET` | Your webhook signing secret |
|
|
101
|
+
|
|
102
|
+
Copy `.env.example` → `.env` and fill in your credentials.
|
|
103
|
+
|
|
104
|
+
## Error Handling
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
begin
|
|
108
|
+
result = client.create_payment(amount: 500, reference_id: "REF", return_url: "")
|
|
109
|
+
rescue Peyemapi::Error => e
|
|
110
|
+
puts "API Error [#{e.status_code}]: #{e.message}"
|
|
111
|
+
rescue Peyemapi::ConfigurationError => e
|
|
112
|
+
puts "Config Error: #{e.message}"
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Running Tests
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
bundle install
|
|
120
|
+
bundle exec rspec
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Publishing to RubyGems
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
gem build peyemapi-sdk.gemspec
|
|
127
|
+
gem push peyemapi-sdk-1.0.0.gem
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require "faraday"
|
|
2
|
+
require "faraday/multipart"
|
|
3
|
+
require "openssl"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module Peyemapi
|
|
7
|
+
class Client
|
|
8
|
+
DEFAULT_API_URL = "https://fyxmoljbnionrylsmfoo.supabase.co/functions/v1/bazik-api"
|
|
9
|
+
|
|
10
|
+
# @param secret_key [String, nil] API secret key. Falls back to PEYEM_API_KEY env var.
|
|
11
|
+
# @param api_url [String, nil] Override the API base URL. Falls back to PEYEM_API_URL env var.
|
|
12
|
+
# @param timeout [Integer] HTTP timeout in seconds (default: 30).
|
|
13
|
+
def initialize(secret_key = nil, api_url: nil, timeout: 30)
|
|
14
|
+
@secret_key = secret_key || ENV["PEYEM_API_KEY"].to_s
|
|
15
|
+
|
|
16
|
+
if @secret_key.empty?
|
|
17
|
+
raise Peyemapi::ConfigurationError.new(
|
|
18
|
+
"API Secret Key is required. Pass it to the constructor or set the PEYEM_API_KEY environment variable."
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
base_url = api_url || ENV["PEYEM_API_URL"] || DEFAULT_API_URL
|
|
23
|
+
@conn = Faraday.new(url: base_url.chomp("/")) do |f|
|
|
24
|
+
f.request :json
|
|
25
|
+
f.response :json, content_type: /\bjson$/
|
|
26
|
+
f.options.timeout = timeout
|
|
27
|
+
f.headers["Authorization"] = "Bearer #{@secret_key}"
|
|
28
|
+
f.headers["Accept"] = "application/json"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# ──────────────────────────────────────────────────────────────────
|
|
33
|
+
# Public API methods
|
|
34
|
+
# ──────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
# Create a payment.
|
|
37
|
+
#
|
|
38
|
+
# @param amount [Numeric] Amount in HTG (e.g. 500)
|
|
39
|
+
# @param reference_id [String] Unique order ID (e.g. "ORDER-123")
|
|
40
|
+
# @param return_url [String] URL to redirect after payment
|
|
41
|
+
# @param description [String] Optional description
|
|
42
|
+
# @return [Hash] API response (may contain +payment_url+)
|
|
43
|
+
def create_payment(amount:, reference_id:, return_url: "", description: "Paiement commande")
|
|
44
|
+
request(:post, "/pay", {
|
|
45
|
+
amount: amount,
|
|
46
|
+
referenceId: reference_id,
|
|
47
|
+
description: description,
|
|
48
|
+
returnUrl: return_url
|
|
49
|
+
})
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Check the status of a payment.
|
|
53
|
+
#
|
|
54
|
+
# @param reference_id [String] The reference ID used when creating the payment
|
|
55
|
+
# @return [Hash] API response with +status+, +amount+, etc.
|
|
56
|
+
def check_status(reference_id)
|
|
57
|
+
request(:get, "/status", nil, params: { referenceId: reference_id })
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Get the account balance.
|
|
61
|
+
#
|
|
62
|
+
# @return [Hash] API response with +balance+ and +currency+
|
|
63
|
+
def get_balance
|
|
64
|
+
request(:get, "/balance")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Verify an incoming webhook signature using HMAC-SHA256.
|
|
68
|
+
#
|
|
69
|
+
# @param payload [String] Raw request body string
|
|
70
|
+
# @param signature [String] Value from X-Webhook-Signature header
|
|
71
|
+
# @param webhook_secret [String] Your webhook secret (whsec_...)
|
|
72
|
+
# @return [Boolean]
|
|
73
|
+
def self.verify_webhook(payload, signature, webhook_secret)
|
|
74
|
+
expected = OpenSSL::HMAC.hexdigest("SHA256", webhook_secret, payload)
|
|
75
|
+
ActiveSupport::SecurityUtils.secure_compare(expected, signature)
|
|
76
|
+
rescue NameError
|
|
77
|
+
# Fallback when ActiveSupport is not available (non-Rails)
|
|
78
|
+
OpenSSL.fixed_length_secure_compare(expected, signature)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# ──────────────────────────────────────────────────────────────────
|
|
82
|
+
private
|
|
83
|
+
# ──────────────────────────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
def request(method, path, body = nil, params: {})
|
|
86
|
+
response =
|
|
87
|
+
if method == :post
|
|
88
|
+
@conn.post(path) { |req| req.body = body }
|
|
89
|
+
else
|
|
90
|
+
@conn.get(path) { |req| req.params.merge!(params) }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
data = response.body || {}
|
|
94
|
+
|
|
95
|
+
unless response.success?
|
|
96
|
+
message = data.is_a?(Hash) ? data["message"] : "API request failed"
|
|
97
|
+
raise Peyemapi::Error.new(
|
|
98
|
+
message || "API request failed with status #{response.status}",
|
|
99
|
+
status_code: response.status
|
|
100
|
+
)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
data
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Peyemapi
|
|
2
|
+
# Raised when the PeyemAPI returns an error response.
|
|
3
|
+
class Error < StandardError
|
|
4
|
+
attr_reader :status_code
|
|
5
|
+
|
|
6
|
+
def initialize(message, status_code: 0)
|
|
7
|
+
super(message)
|
|
8
|
+
@status_code = status_code
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Raised when required configuration is missing.
|
|
13
|
+
class ConfigurationError < Error; end
|
|
14
|
+
end
|
data/lib/peyemapi.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require "peyemapi/version"
|
|
2
|
+
require "peyemapi/client"
|
|
3
|
+
require "peyemapi/error"
|
|
4
|
+
|
|
5
|
+
module Peyemapi
|
|
6
|
+
class << self
|
|
7
|
+
# Shorthand to create a client
|
|
8
|
+
# Peyemapi.client("sk_user_...")
|
|
9
|
+
def client(secret_key = nil, **options)
|
|
10
|
+
Client.new(secret_key, **options)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: peyemapi-sdk
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Antigravity
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-30 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: faraday
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.12'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.12'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: webmock
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.18'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.18'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: dotenv
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rake
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '13.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '13.0'
|
|
83
|
+
description: A lightweight, framework-agnostic Ruby SDK for integrating PeyemAPI payments.
|
|
84
|
+
Works with Rails, Sinatra, Hanami, and plain Ruby.
|
|
85
|
+
email:
|
|
86
|
+
executables: []
|
|
87
|
+
extensions: []
|
|
88
|
+
extra_rdoc_files: []
|
|
89
|
+
files:
|
|
90
|
+
- README.md
|
|
91
|
+
- lib/peyemapi.rb
|
|
92
|
+
- lib/peyemapi/client.rb
|
|
93
|
+
- lib/peyemapi/error.rb
|
|
94
|
+
- lib/peyemapi/version.rb
|
|
95
|
+
homepage: https://github.com/peyemapi/peyemapi-ruby-sdk
|
|
96
|
+
licenses:
|
|
97
|
+
- MIT
|
|
98
|
+
metadata: {}
|
|
99
|
+
post_install_message:
|
|
100
|
+
rdoc_options: []
|
|
101
|
+
require_paths:
|
|
102
|
+
- lib
|
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
104
|
+
requirements:
|
|
105
|
+
- - ">="
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: 3.0.0
|
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
|
+
requirements:
|
|
110
|
+
- - ">="
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: '0'
|
|
113
|
+
requirements: []
|
|
114
|
+
rubygems_version: 3.0.3.1
|
|
115
|
+
signing_key:
|
|
116
|
+
specification_version: 4
|
|
117
|
+
summary: Ruby SDK for PeyemAPI — Haitian payment gateway
|
|
118
|
+
test_files: []
|