bayarcash 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/CHANGELOG.md +21 -0
- data/LICENSE +21 -0
- data/README.md +517 -0
- data/bayarcash.gemspec +32 -0
- data/lib/bayarcash/callback_verifications.rb +177 -0
- data/lib/bayarcash/checksum_generator.rb +110 -0
- data/lib/bayarcash/client.rb +293 -0
- data/lib/bayarcash/duit_now/dobw.rb +33 -0
- data/lib/bayarcash/errors.rb +49 -0
- data/lib/bayarcash/fpx.rb +26 -0
- data/lib/bayarcash/fpx_direct_debit.rb +75 -0
- data/lib/bayarcash/fpx_direct_debit_payment_intent.rb +70 -0
- data/lib/bayarcash/makes_http_requests.rb +143 -0
- data/lib/bayarcash/manual_bank_transfer.rb +224 -0
- data/lib/bayarcash/resources/fpx_bank_resource.rb +11 -0
- data/lib/bayarcash/resources/fpx_direct_debit_application_resource.rb +12 -0
- data/lib/bayarcash/resources/fpx_direct_debit_resource.rb +15 -0
- data/lib/bayarcash/resources/payment_intent_resource.rb +13 -0
- data/lib/bayarcash/resources/portal_resource.rb +14 -0
- data/lib/bayarcash/resources/resource.rb +90 -0
- data/lib/bayarcash/resources/transaction_resource.rb +14 -0
- data/lib/bayarcash/security_utils.rb +37 -0
- data/lib/bayarcash/util.rb +92 -0
- data/lib/bayarcash/version.rb +5 -0
- data/lib/bayarcash.rb +41 -0
- metadata +152 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 32732f286c3d5b6b7ad274070f23e57ce920a402cf87cc31a92d03aca732b485
|
|
4
|
+
data.tar.gz: 4acc4a3c0f1ad14d4c4dd44f639d58180362391d50333c0cabf19ee9e60be943
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 8c446510e6a77b961c38de5b25f27ae82606c56710a6e379e5efdba567bc4aa2d35fd27e8ad32404bf801b93128b3b2b3f95b83f9f9d6044cc1383a53c8f30c6
|
|
7
|
+
data.tar.gz: af2cb351ec18187b7629c84c9325bb42fbb0b432f50635bf2a5b88ac6b83a86c6fdac2dd1d268cb3c6db06382066b74c4439807576abf80f34dd30bf7ed1c319
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## 3.0.0 - 2026-07-22
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Initial release of the Ruby SDK for the Bayarcash payment gateway — an idiomatic,
|
|
9
|
+
framework-agnostic port of the official PHP SDK.
|
|
10
|
+
- Support for API **v2** (default) and **v3**, including the v3-only transaction
|
|
11
|
+
queries, payment-intent retrieval and cancellation.
|
|
12
|
+
- Checksum generation (HMAC-SHA256) for payment intents and FPX Direct Debit
|
|
13
|
+
enrolment/maintenance, byte-compatible with the gateway.
|
|
14
|
+
- Callback verification for every callback type (pre-transaction, transaction,
|
|
15
|
+
return-url, direct-debit bank approval, authorization and transaction) using a
|
|
16
|
+
constant-time checksum comparison.
|
|
17
|
+
- FPX Direct Debit mandate operations and Manual Bank Transfer (with multipart
|
|
18
|
+
`proof_of_payment` upload and status update).
|
|
19
|
+
- Payment-channel constants, status classes (`Fpx`, `FpxDirectDebit`,
|
|
20
|
+
`DuitNow::Dobw`), and typed response objects tolerant of omitted fields.
|
|
21
|
+
- Typed errors mapping HTTP status codes (422, 404, 400, 429 and a generic fallback).
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Web Impian
|
|
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.
|
data/README.md
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
# Bayarcash Payment Gateway Ruby SDK
|
|
2
|
+
|
|
3
|
+
[](https://rubygems.org/gems/bayarcash)
|
|
4
|
+
[](https://rubygems.org/gems/bayarcash)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
The [Bayarcash](https://bayarcash.com/) Ruby SDK provides an expressive, framework-agnostic
|
|
8
|
+
interface for interacting with Bayarcash's Payment Gateway API. It is an idiomatic Ruby port
|
|
9
|
+
of the official PHP SDK and supports both API **v2** (default) and **v3**, with additional
|
|
10
|
+
query features available in v3.
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
- [Requirements](#requirements)
|
|
15
|
+
- [Installation](#installation)
|
|
16
|
+
- [Getting Started](#getting-started)
|
|
17
|
+
- [Configuration](#configuration)
|
|
18
|
+
- [Quick Start: Accept a Payment](#quick-start-accept-a-payment)
|
|
19
|
+
- [Payment Channels](#payment-channels)
|
|
20
|
+
- [Creating a Payment Intent](#creating-a-payment-intent)
|
|
21
|
+
- [Handling Callbacks](#handling-callbacks)
|
|
22
|
+
- [Payment & Transaction Status](#payment--transaction-status)
|
|
23
|
+
- [Transactions](#transactions)
|
|
24
|
+
- [FPX Direct Debit](#fpx-direct-debit)
|
|
25
|
+
- [Manual Bank Transfer](#manual-bank-transfer)
|
|
26
|
+
- [Portals & FPX Banks](#portals--fpx-banks)
|
|
27
|
+
- [Error Handling](#error-handling)
|
|
28
|
+
- [Response Objects](#response-objects)
|
|
29
|
+
- [Security Recommendations](#security-recommendations)
|
|
30
|
+
- [Development](#development)
|
|
31
|
+
- [Support](#support)
|
|
32
|
+
|
|
33
|
+
## Requirements
|
|
34
|
+
|
|
35
|
+
- Ruby >= 2.7
|
|
36
|
+
- [Faraday](https://github.com/lostisland/faraday) 1.10+ / 2.x (installed automatically)
|
|
37
|
+
- `faraday-multipart` (installed automatically, used for the manual-transfer file upload)
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
Add to your `Gemfile`:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
gem "bayarcash"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then run:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
bundle install
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or install it directly:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
gem install bayarcash
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
You will need two credentials from your Bayarcash console:
|
|
60
|
+
|
|
61
|
+
- **API token** — used to authenticate SDK requests.
|
|
62
|
+
- **API secret key** — used to generate request checksums and verify callbacks.
|
|
63
|
+
|
|
64
|
+
## Getting Started
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
require "bayarcash"
|
|
68
|
+
|
|
69
|
+
bayarcash = Bayarcash::Client.new("YOUR_API_TOKEN")
|
|
70
|
+
bayarcash.use_sandbox # remove this line in production
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The client is a plain object — use it from any framework (Rails, Sinatra, Hanami, a plain
|
|
74
|
+
script, …). Nothing global is configured.
|
|
75
|
+
|
|
76
|
+
### Configuration
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
bayarcash
|
|
80
|
+
.use_sandbox # switch to the sandbox environment
|
|
81
|
+
.set_api_version("v3") # "v2" (default) or "v3"
|
|
82
|
+
.set_timeout(60) # request timeout in seconds (default 30)
|
|
83
|
+
|
|
84
|
+
bayarcash.get_api_version # => "v3"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
You can also configure everything on construction:
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
bayarcash = Bayarcash::Client.new(
|
|
91
|
+
"YOUR_API_TOKEN",
|
|
92
|
+
sandbox: true,
|
|
93
|
+
api_version: "v3",
|
|
94
|
+
timeout: 60
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
> Call `use_sandbox` / `set_api_version` **before** making requests. Omit `use_sandbox` in
|
|
99
|
+
> production to hit the live gateway.
|
|
100
|
+
|
|
101
|
+
## Quick Start: Accept a Payment
|
|
102
|
+
|
|
103
|
+
A complete FPX payment flow, from creating the payment to verifying the result:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
require "bayarcash"
|
|
107
|
+
|
|
108
|
+
bayarcash = Bayarcash::Client.new("YOUR_API_TOKEN")
|
|
109
|
+
bayarcash.use_sandbox
|
|
110
|
+
|
|
111
|
+
api_secret_key = "YOUR_API_SECRET_KEY"
|
|
112
|
+
|
|
113
|
+
# 1. Build the payment request
|
|
114
|
+
data = {
|
|
115
|
+
"portal_key" => "your_portal_key",
|
|
116
|
+
"payment_channel" => Bayarcash::Client::FPX,
|
|
117
|
+
"order_number" => "INV-1001",
|
|
118
|
+
"amount" => "10.00",
|
|
119
|
+
"payer_name" => "Ahmad bin Abdullah",
|
|
120
|
+
"payer_email" => "ahmad@example.com",
|
|
121
|
+
"payer_telephone_number" => "0123456789",
|
|
122
|
+
"return_url" => "https://your-site.com/payment/return",
|
|
123
|
+
"callback_url" => "https://your-site.com/payment/callback"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# 2. Sign it (recommended)
|
|
127
|
+
data["checksum"] = bayarcash.create_payment_intent_checksum_value(api_secret_key, data)
|
|
128
|
+
|
|
129
|
+
# 3. Create the payment intent and redirect the payer to Bayarcash
|
|
130
|
+
payment_intent = bayarcash.create_payment_intent(data)
|
|
131
|
+
|
|
132
|
+
redirect_to payment_intent.url # or: response.headers["Location"] = payment_intent.url
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
After payment, Bayarcash calls your `callback_url` (server-to-server) and redirects the payer
|
|
136
|
+
to your `return_url`. Verify both — see [Handling Callbacks](#handling-callbacks).
|
|
137
|
+
|
|
138
|
+
## Payment Channels
|
|
139
|
+
|
|
140
|
+
Pass one of these constants (or an array of them) as `payment_channel`:
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
Bayarcash::Client::FPX # FPX Online Banking (1)
|
|
144
|
+
Bayarcash::Client::MANUAL_TRANSFER # Manual Bank Transfer (2)
|
|
145
|
+
Bayarcash::Client::FPX_DIRECT_DEBIT # FPX Direct Debit (3)
|
|
146
|
+
Bayarcash::Client::FPX_LINE_OF_CREDIT # FPX Line of Credit (4)
|
|
147
|
+
Bayarcash::Client::DUITNOW_DOBW # DuitNow Online Banking (5)
|
|
148
|
+
Bayarcash::Client::DUITNOW_QR # DuitNow QR (6)
|
|
149
|
+
Bayarcash::Client::SPAYLATER # ShopeePayLater (7)
|
|
150
|
+
Bayarcash::Client::BOOST_PAYFLEX # Boost PayFlex (8)
|
|
151
|
+
Bayarcash::Client::QRISOB # QRIS Online Banking (9)
|
|
152
|
+
Bayarcash::Client::QRISWALLET # QRIS Wallet (10)
|
|
153
|
+
Bayarcash::Client::NETS # NETS (11)
|
|
154
|
+
Bayarcash::Client::CREDIT_CARD # Credit Card (12)
|
|
155
|
+
Bayarcash::Client::ALIPAY # Alipay (13)
|
|
156
|
+
Bayarcash::Client::WECHATPAY # WeChat Pay (14)
|
|
157
|
+
Bayarcash::Client::PROMPTPAY # PromptPay (15)
|
|
158
|
+
Bayarcash::Client::TOUCH_N_GO # Touch 'n Go eWallet (16)
|
|
159
|
+
Bayarcash::Client::BOOST_WALLET # Boost Wallet (17)
|
|
160
|
+
Bayarcash::Client::GRABPAY # GrabPay (18)
|
|
161
|
+
Bayarcash::Client::GRABPL # Grab PayLater (19)
|
|
162
|
+
Bayarcash::Client::SHOPEE_PAY # ShopeePay (21)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
> Note there is intentionally no channel id `20` — `SHOPEE_PAY` is `21`.
|
|
166
|
+
|
|
167
|
+
## Creating a Payment Intent
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
payment_intent = bayarcash.create_payment_intent(data)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Request fields:**
|
|
174
|
+
|
|
175
|
+
| Field | Required | Description |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| `portal_key` | ✅ | Your portal key. |
|
|
178
|
+
| `order_number` | ✅ | Your reference. Max 30 chars. |
|
|
179
|
+
| `amount` | ✅ | String with up to 2 decimals, e.g. `"10.00"`. Range `1.00`–`30000.00` (min differs for some channels). |
|
|
180
|
+
| `payer_name` | ✅ | Max 150 chars. |
|
|
181
|
+
| `payer_email` | ✅ | Valid email, max 250 chars. |
|
|
182
|
+
| `payment_channel` | ➖ | A `Bayarcash::Client::*` channel id, or an array of ids. If omitted, the payer chooses on the Bayarcash page. |
|
|
183
|
+
| `payer_telephone_number` | ➖ | Required for e-wallet / DuitNow channels. Max 20 chars. |
|
|
184
|
+
| `return_url` | ➖ | Where the payer's browser is redirected after payment. |
|
|
185
|
+
| `callback_url` | ➖ | Server-to-server notification URL. |
|
|
186
|
+
| `metadata` | ➖ | Any extra data you want echoed back. |
|
|
187
|
+
| `checksum` | ➖ | Recommended. See below. |
|
|
188
|
+
|
|
189
|
+
### Checksum
|
|
190
|
+
|
|
191
|
+
The checksum protects the request from tampering. Generate it **after** building the request
|
|
192
|
+
and append it as `checksum`:
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
data["checksum"] = bayarcash.create_payment_intent_checksum_value(api_secret_key, data)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The checksum is computed from `payment_channel`, `order_number`, `amount`, `payer_name`, and
|
|
199
|
+
`payer_email` (sorted by key, values joined with `|`, then HMAC-SHA256 with your secret key).
|
|
200
|
+
|
|
201
|
+
## Handling Callbacks
|
|
202
|
+
|
|
203
|
+
Bayarcash sends **two kinds** of notification. Always verify them with your API secret key
|
|
204
|
+
before trusting the data.
|
|
205
|
+
|
|
206
|
+
| Notification | How it arrives | Read it from |
|
|
207
|
+
|---|---|---|
|
|
208
|
+
| `callback_url` (transaction) | Server-to-server **POST** (form-encoded) | `request.POST` / `params` |
|
|
209
|
+
| `return_url` (payer redirect) | Browser redirect — **POST** on v2, **GET** query on v3 | `params` |
|
|
210
|
+
|
|
211
|
+
```ruby
|
|
212
|
+
callback_data = params.to_unsafe_h # Rails; or any Hash of the callback params
|
|
213
|
+
|
|
214
|
+
# Transaction callback (sent to your callback_url)
|
|
215
|
+
if bayarcash.verify_transaction_callback_data(callback_data, api_secret_key)
|
|
216
|
+
# Data is authentic — safe to process.
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Payer redirect (sent to your return_url)
|
|
220
|
+
if bayarcash.verify_return_url_callback_data(callback_data, api_secret_key)
|
|
221
|
+
# ...
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Pre-transaction callback (sent before the transaction record)
|
|
225
|
+
if bayarcash.verify_pre_transaction_callback_data(callback_data, api_secret_key)
|
|
226
|
+
# ...
|
|
227
|
+
end
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Each verifier returns `true` only when the checksum matches, using a **constant-time
|
|
231
|
+
comparison** to resist timing attacks. Callback keys may be strings or symbols. See
|
|
232
|
+
[FPX Direct Debit](#fpx-direct-debit) for mandate-specific callback verifiers.
|
|
233
|
+
|
|
234
|
+
## Payment & Transaction Status
|
|
235
|
+
|
|
236
|
+
Transaction status is an integer code. Use the `Fpx` helper instead of hardcoding numbers:
|
|
237
|
+
|
|
238
|
+
```ruby
|
|
239
|
+
Bayarcash::Fpx::STATUS_NEW # 0
|
|
240
|
+
Bayarcash::Fpx::STATUS_PENDING # 1
|
|
241
|
+
Bayarcash::Fpx::STATUS_FAILED # 2
|
|
242
|
+
Bayarcash::Fpx::STATUS_SUCCESS # 3
|
|
243
|
+
Bayarcash::Fpx::STATUS_CANCELLED # 4
|
|
244
|
+
|
|
245
|
+
if callback_data["status"].to_i == Bayarcash::Fpx::STATUS_SUCCESS
|
|
246
|
+
# Payment successful
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
Bayarcash::Fpx.get_status_text(callback_data["status"].to_i) # e.g. "Successful"
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
DuitNow (DOBW) statuses live on `Bayarcash::DuitNow::Dobw`, and mandate statuses on
|
|
253
|
+
`Bayarcash::FpxDirectDebit`.
|
|
254
|
+
|
|
255
|
+
## Transactions
|
|
256
|
+
|
|
257
|
+
```ruby
|
|
258
|
+
# Get a single transaction (v2 and v3)
|
|
259
|
+
transaction = bayarcash.get_transaction("transaction_id")
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The following query helpers require **API v3** and raise on v2:
|
|
263
|
+
|
|
264
|
+
```ruby
|
|
265
|
+
bayarcash.set_api_version("v3")
|
|
266
|
+
|
|
267
|
+
result = bayarcash.get_all_transactions(
|
|
268
|
+
order_number: "INV-1001",
|
|
269
|
+
status: "3",
|
|
270
|
+
payment_channel: Bayarcash::Client::FPX,
|
|
271
|
+
exchange_reference_number: "REF123",
|
|
272
|
+
payer_email: "ahmad@example.com"
|
|
273
|
+
)
|
|
274
|
+
# result[:data] => Array<TransactionResource>, result[:meta] => pagination meta
|
|
275
|
+
|
|
276
|
+
by_order = bayarcash.get_transaction_by_order_number("INV-1001")
|
|
277
|
+
by_email = bayarcash.get_transactions_by_payer_email("ahmad@example.com")
|
|
278
|
+
by_status = bayarcash.get_transactions_by_status("3")
|
|
279
|
+
by_channel = bayarcash.get_transactions_by_payment_channel(Bayarcash::Client::FPX)
|
|
280
|
+
by_ref = bayarcash.get_transaction_by_reference_number("REF123") # single or nil
|
|
281
|
+
|
|
282
|
+
# Get a payment intent by id (v3 only)
|
|
283
|
+
intent = bayarcash.get_payment_intent("payment_intent_id")
|
|
284
|
+
|
|
285
|
+
# Cancel a payment intent (v3 only)
|
|
286
|
+
bayarcash.cancel_payment_intent("payment_intent_id")
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## FPX Direct Debit
|
|
290
|
+
|
|
291
|
+
FPX Direct Debit lets you set up a recurring mandate and later maintain or terminate it.
|
|
292
|
+
Constants live on the `FpxDirectDebit` class:
|
|
293
|
+
|
|
294
|
+
```ruby
|
|
295
|
+
# Payer ID type
|
|
296
|
+
Bayarcash::FpxDirectDebit::NRIC # 1 (New IC)
|
|
297
|
+
Bayarcash::FpxDirectDebit::OLD_IC # 2
|
|
298
|
+
Bayarcash::FpxDirectDebit::PASSPORT # 3
|
|
299
|
+
Bayarcash::FpxDirectDebit::BUSINESS_REGISTRATION # 4
|
|
300
|
+
Bayarcash::FpxDirectDebit::OTHERS # 5
|
|
301
|
+
|
|
302
|
+
# Frequency mode
|
|
303
|
+
Bayarcash::FpxDirectDebit::MODE_DAILY # "DL"
|
|
304
|
+
Bayarcash::FpxDirectDebit::MODE_WEEKLY # "WK"
|
|
305
|
+
Bayarcash::FpxDirectDebit::MODE_MONTHLY # "MT"
|
|
306
|
+
Bayarcash::FpxDirectDebit::MODE_YEARLY # "YR"
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### 1. Enrolment
|
|
310
|
+
|
|
311
|
+
```ruby
|
|
312
|
+
data = {
|
|
313
|
+
"portal_key" => "your_portal_key",
|
|
314
|
+
"order_number" => "DD-1001",
|
|
315
|
+
"amount" => "10.00", # range 5.00–30000.00
|
|
316
|
+
"payer_name" => "Ahmad bin Abdullah",
|
|
317
|
+
"payer_id_type" => Bayarcash::FpxDirectDebit::NRIC,
|
|
318
|
+
"payer_id" => "900101011234",
|
|
319
|
+
"payer_email" => "ahmad@example.com", # max 27 chars
|
|
320
|
+
"payer_telephone_number" => "0123456789",
|
|
321
|
+
"application_reason" => "Monthly subscription",
|
|
322
|
+
"frequency_mode" => Bayarcash::FpxDirectDebit::MODE_MONTHLY,
|
|
323
|
+
"effective_date" => "2026-08-01", # optional, Y-m-d
|
|
324
|
+
"expiry_date" => "2027-08-01", # optional, Y-m-d
|
|
325
|
+
"return_url" => "https://your-site.com/mandate/return"
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
data["checksum"] = bayarcash.create_fpx_direct_debit_enrolment_checksum_value(api_secret_key, data)
|
|
329
|
+
|
|
330
|
+
mandate = bayarcash.create_fpx_direct_debit_enrollment(data)
|
|
331
|
+
redirect_to mandate.url # redirect payer to the enrolment page
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### 2. Maintenance
|
|
335
|
+
|
|
336
|
+
Update an existing mandate (identified by its mandate id):
|
|
337
|
+
|
|
338
|
+
```ruby
|
|
339
|
+
data = {
|
|
340
|
+
"amount" => "15.00",
|
|
341
|
+
"payer_email" => "ahmad@example.com",
|
|
342
|
+
"payer_telephone_number" => "0123456789",
|
|
343
|
+
"application_reason" => "Update amount",
|
|
344
|
+
"frequency_mode" => Bayarcash::FpxDirectDebit::MODE_MONTHLY
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
data["checksum"] = bayarcash.create_fpx_direct_debit_maintenance_checksum_value(api_secret_key, data)
|
|
348
|
+
|
|
349
|
+
mandate = bayarcash.create_fpx_direct_debit_maintenance(mandate_id, data)
|
|
350
|
+
redirect_to mandate.url
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### 3. Termination
|
|
354
|
+
|
|
355
|
+
```ruby
|
|
356
|
+
mandate = bayarcash.create_fpx_direct_debit_termination(mandate_id, {
|
|
357
|
+
"application_reason" => "Customer cancelled"
|
|
358
|
+
})
|
|
359
|
+
redirect_to mandate.url
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Retrieving mandates & verifying mandate callbacks
|
|
363
|
+
|
|
364
|
+
```ruby
|
|
365
|
+
mandate = bayarcash.get_fpx_direct_debit(mandate_id)
|
|
366
|
+
transaction = bayarcash.get_fpx_direct_debit_transaction(transaction_id)
|
|
367
|
+
|
|
368
|
+
# Mandate callback verifiers
|
|
369
|
+
bayarcash.verify_direct_debit_bank_approval_callback_data(callback_data, api_secret_key)
|
|
370
|
+
bayarcash.verify_direct_debit_authorization_callback_data(callback_data, api_secret_key)
|
|
371
|
+
bayarcash.verify_direct_debit_transaction_callback_data(callback_data, api_secret_key)
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
> The direct-debit **authorization** verifier includes the `application_type` field, exactly
|
|
375
|
+
> as the gateway signs it.
|
|
376
|
+
|
|
377
|
+
## Manual Bank Transfer
|
|
378
|
+
|
|
379
|
+
Submit a manual (offline) bank transfer with proof of payment:
|
|
380
|
+
|
|
381
|
+
```ruby
|
|
382
|
+
response = bayarcash.create_manual_bank_transfer({
|
|
383
|
+
"portal_key" => "your_portal_key",
|
|
384
|
+
"payment_gateway" => Bayarcash::Client::MANUAL_TRANSFER, # must be 2
|
|
385
|
+
"order_no" => "MT-1001",
|
|
386
|
+
"buyer_name" => "Ahmad bin Abdullah",
|
|
387
|
+
"buyer_email" => "ahmad@example.com",
|
|
388
|
+
"buyer_tel_no" => "0123456789", # optional
|
|
389
|
+
"order_amount" => "10.00",
|
|
390
|
+
"merchant_bank_name" => "Maybank",
|
|
391
|
+
"merchant_bank_account" => "1234567890",
|
|
392
|
+
"merchant_bank_account_holder" => "Your Company Sdn Bhd",
|
|
393
|
+
"bank_transfer_type" => "Internet Banking", # or "Cash Deposit Machine (CDM)"
|
|
394
|
+
"bank_transfer_notes" => "Payment for order MT-1001",
|
|
395
|
+
"bank_transfer_date" => "2026-07-22", # optional, defaults to today
|
|
396
|
+
"proof_of_payment" => "/path/to/receipt.jpg" # jpeg/png/gif/pdf, max 10 MB
|
|
397
|
+
})
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Update the status of an existing transfer:
|
|
401
|
+
|
|
402
|
+
```ruby
|
|
403
|
+
bayarcash.update_manual_bank_transfer_status(
|
|
404
|
+
"ref_no_here",
|
|
405
|
+
Bayarcash::Fpx::STATUS_SUCCESS.to_s,
|
|
406
|
+
"10.00"
|
|
407
|
+
)
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## Portals & FPX Banks
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
# All portals for your account
|
|
414
|
+
portals = bayarcash.get_portals
|
|
415
|
+
|
|
416
|
+
# Payment channels available for a portal
|
|
417
|
+
channels = bayarcash.get_channels("your_portal_key")
|
|
418
|
+
|
|
419
|
+
# FPX banks (for building a bank selector)
|
|
420
|
+
banks = bayarcash.fpx_banks_list
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Error Handling
|
|
424
|
+
|
|
425
|
+
Failed API calls raise typed errors. Rescue them to handle failures gracefully:
|
|
426
|
+
|
|
427
|
+
```ruby
|
|
428
|
+
begin
|
|
429
|
+
payment_intent = bayarcash.create_payment_intent(data)
|
|
430
|
+
rescue Bayarcash::ValidationError => e
|
|
431
|
+
# 422 — invalid request data
|
|
432
|
+
errors = e.errors
|
|
433
|
+
rescue Bayarcash::NotFoundError => e
|
|
434
|
+
# 404 — resource not found
|
|
435
|
+
rescue Bayarcash::RateLimitExceededError => e
|
|
436
|
+
# 429 — too many requests
|
|
437
|
+
reset_at = e.rate_limit_resets_at # unix timestamp or nil
|
|
438
|
+
rescue Bayarcash::FailedActionError => e
|
|
439
|
+
# 400 — request failed
|
|
440
|
+
message = e.message
|
|
441
|
+
end
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
| Error | HTTP | Meaning |
|
|
445
|
+
|---|---|---|
|
|
446
|
+
| `Bayarcash::ValidationError` | 422 | Invalid data. Call `#errors` for details. |
|
|
447
|
+
| `Bayarcash::FailedActionError` | 400 | Request failed. `#message` has the reason. |
|
|
448
|
+
| `Bayarcash::NotFoundError` | 404 | Resource not found. |
|
|
449
|
+
| `Bayarcash::RateLimitExceededError` | 429 | Rate limited. `#rate_limit_resets_at` holds the reset time. |
|
|
450
|
+
| `Bayarcash::TimeoutError` | — | Raised by the optional `retry_until` helper after a timeout. |
|
|
451
|
+
| `Bayarcash::Error` | other | Base class; also raised for any other non-2xx status. |
|
|
452
|
+
|
|
453
|
+
## Response Objects
|
|
454
|
+
|
|
455
|
+
API methods return typed resource objects with snake_case readers. Common properties:
|
|
456
|
+
|
|
457
|
+
**`PaymentIntentResource`** (from `create_payment_intent` / `get_payment_intent`)
|
|
458
|
+
|
|
459
|
+
```ruby
|
|
460
|
+
payment_intent.url # checkout URL to redirect the payer to
|
|
461
|
+
payment_intent.id
|
|
462
|
+
payment_intent.status
|
|
463
|
+
payment_intent.amount
|
|
464
|
+
payment_intent.order_number
|
|
465
|
+
payment_intent.payer_name
|
|
466
|
+
payment_intent.payer_email
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**`TransactionResource`** (from `get_transaction` / transaction queries)
|
|
470
|
+
|
|
471
|
+
```ruby
|
|
472
|
+
transaction.id
|
|
473
|
+
transaction.status # status code — see Fpx constants
|
|
474
|
+
transaction.status_description
|
|
475
|
+
transaction.amount
|
|
476
|
+
transaction.order_number
|
|
477
|
+
transaction.exchange_reference_number
|
|
478
|
+
transaction.payer_name
|
|
479
|
+
transaction.payer_email
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
Any missing field is `nil`. Convert a resource (including nested resources) to a hash:
|
|
483
|
+
|
|
484
|
+
```ruby
|
|
485
|
+
transaction.to_h
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
## Security Recommendations
|
|
489
|
+
|
|
490
|
+
1. Always send a `checksum` with payment and mandate requests.
|
|
491
|
+
2. Verify **every** callback with the provided verification methods before acting on it.
|
|
492
|
+
3. Store and check transaction ids to prevent duplicate processing.
|
|
493
|
+
4. Use HTTPS for your `return_url` and `callback_url`.
|
|
494
|
+
5. Keep your API token and secret key out of source control.
|
|
495
|
+
|
|
496
|
+
## Development
|
|
497
|
+
|
|
498
|
+
```bash
|
|
499
|
+
bundle install
|
|
500
|
+
bundle exec rspec
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## API Documentation
|
|
504
|
+
|
|
505
|
+
For full API details, see the [Official Bayarcash API Documentation](https://api.webimpian.support/bayarcash).
|
|
506
|
+
|
|
507
|
+
## Support
|
|
508
|
+
|
|
509
|
+
For support questions, contact Bayarcash support or open an issue in this repository.
|
|
510
|
+
|
|
511
|
+
## Changelog
|
|
512
|
+
|
|
513
|
+
See [CHANGELOG.md](CHANGELOG.md) for the version history.
|
|
514
|
+
|
|
515
|
+
## License
|
|
516
|
+
|
|
517
|
+
Open-sourced software licensed under the [MIT license](LICENSE).
|
data/bayarcash.gemspec
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/bayarcash/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "bayarcash"
|
|
7
|
+
spec.version = Bayarcash::VERSION
|
|
8
|
+
spec.authors = ["Web Impian"]
|
|
9
|
+
spec.email = ["support@webimpian.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Ruby SDK for the Bayarcash payment gateway."
|
|
12
|
+
spec.description = "An expressive, framework-agnostic Ruby client for the Bayarcash " \
|
|
13
|
+
"Payment Gateway API. Supports API v2 (default) and v3, checksum " \
|
|
14
|
+
"generation, callback verification, FPX Direct Debit, and Manual Bank Transfer."
|
|
15
|
+
spec.homepage = "https://bayarcash.com/"
|
|
16
|
+
spec.license = "MIT"
|
|
17
|
+
spec.required_ruby_version = ">= 2.7"
|
|
18
|
+
|
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
20
|
+
spec.metadata["source_code_uri"] = "https://github.com/bayarcash/ruby-sdk"
|
|
21
|
+
spec.metadata["changelog_uri"] = "https://github.com/bayarcash/ruby-sdk/blob/main/CHANGELOG.md"
|
|
22
|
+
|
|
23
|
+
spec.files = Dir.glob("lib/**/*.rb") + %w[README.md CHANGELOG.md LICENSE bayarcash.gemspec]
|
|
24
|
+
spec.require_paths = ["lib"]
|
|
25
|
+
|
|
26
|
+
spec.add_dependency "faraday", ">= 1.10", "< 3.0"
|
|
27
|
+
spec.add_dependency "faraday-multipart", ">= 1.0", "< 2.0"
|
|
28
|
+
|
|
29
|
+
spec.add_development_dependency "rspec", "~> 3.12"
|
|
30
|
+
spec.add_development_dependency "webmock", "~> 3.19"
|
|
31
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
32
|
+
end
|