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 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
+ [![Gem Version](https://img.shields.io/gem/v/bayarcash.svg)](https://rubygems.org/gems/bayarcash)
4
+ [![Gem Downloads](https://img.shields.io/gem/dt/bayarcash.svg)](https://rubygems.org/gems/bayarcash)
5
+ [![License](https://img.shields.io/github/license/bayarcash/ruby-sdk.svg)](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