Monnify   F
last analyzed

Complexity

Total Complexity 77

Size/Duplication

Total Lines 1009
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 77
eloc 286
c 4
b 0
f 0
dl 0
loc 1009
rs 2.24

40 Methods

Rating   Name   Duplication   Size   Complexity  
A deallocateReservedAccount() 0 13 2
A withOAuth2() 0 8 2
A getBanks() 0 12 2
B reserveAccount() 0 36 10
A getSubAccounts() 0 12 2
A getAllTransactionsForReservedAccount() 0 13 2
A updateReservedAccountSplitConfig() 0 13 2
A __construct() 0 5 1
A createSubAccounts() 0 12 2
A sourceAccountRestriction() 0 16 2
A getReservedAccountDetails() 0 13 2
A deleteSubAccount() 0 12 2
A getInstanceName() 0 3 1
A createSubAccount() 0 21 2
A calculateTransactionHash() 0 4 1
A withBasicAuth() 0 4 1
A updateSubAccount() 0 22 2
A getBanksWithUSSDShortCode() 0 12 2
A getAllTransactions() 0 12 2
A getToken() 0 14 2
A initializeTransaction() 0 26 3
A getWalletBalance() 0 11 2
A getTransferDetails() 0 12 2
A initiateTransferSingle() 0 20 2
A getBulkTransferDetails() 0 3 1
A validateBankAccount() 0 12 2
A authorizeBulkTransfer2FA() 0 3 1
A resendOTP() 0 13 2
A getSingleTransferDetails() 0 3 1
A listAllTransfers() 0 12 2
A getTransactionStatus() 0 12 2
A authorizeTransfer2FA() 0 15 2
A getBulkTransferTransactions() 0 11 2
A getSingleTransferTransactions() 0 3 1
A initiateTransferBulk() 0 20 2
A calculateTransactionHashFix() 0 4 1
A initiateTransferSingleWithMonnifyTransaction() 0 3 1
A authorizeSingleTransfer2FA() 0 3 1
A getAllBulkTransferTransactions() 0 3 1
A payWithBankTransfer() 0 15 2

How to fix   Complexity   

Complex Class

Complex classes like Monnify often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Monnify, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Created By: Henry Ejemuta
4
 * Project: laravel-monnify
5
 * Class Name: Monnify.php
6
 * Date Created: 7/13/20
7
 * Time Created: 7:55 PM
8
 */
9
10
namespace HenryEjemuta\LaravelMonnify;
11
12
use HenryEjemuta\LaravelMonnify\Classes\MonnifyAllowedPaymentSources;
13
use HenryEjemuta\LaravelMonnify\Classes\MonnifyBankAccount;
14
use HenryEjemuta\LaravelMonnify\Classes\MonnifyIncomeSplitConfig;
15
use HenryEjemuta\LaravelMonnify\Classes\MonnifyOnFailureValidate;
16
use HenryEjemuta\LaravelMonnify\Classes\MonnifyPaymentMethods;
17
use HenryEjemuta\LaravelMonnify\Classes\MonnifyTransaction;
18
use HenryEjemuta\LaravelMonnify\Classes\MonnifyTransactionList;
19
use HenryEjemuta\LaravelMonnify\Exceptions\MonnifyFailedRequestException;
20
use HenryEjemuta\LaravelMonnify\Exceptions\MonnifyInvalidParameterException;
21
use Illuminate\Support\Facades\Http;
22
23
/**
24
 * Class Monnify
25
 * @package HenryEjemuta\LaravelMonnify
26
 *
27
 * This is a Laravel wrapper around the Monnify API hence all failed request will throw MonnifyFailedRequestException with the appropriate message from the Monnify API as well as error code
28
 *
29
 * @link https://docs.teamapt.com/display/MON/Monnify+API+Docs for any error details as well as status code to gracefully handle them within your application
30
 *
31
 */
32
class Monnify
33
{
34
    /**
35
     * base url
36
     *
37
     * @var
38
     */
39
    private $baseUrl;
40
    private $v1 = "/api/v1/";
41
    private $v2 = "/api/v2/";
42
43
    /**
44
     * the cart session key
45
     *
46
     * @var
47
     */
48
    protected $instanceName;
49
50
    /**
51
     * Flexible handle to the Monnify Configuration
52
     *
53
     * @var
54
     */
55
    protected $config;
56
57
    /**
58
     * Http Client for remote request handling
59
     * @var Http
60
     */
61
    private $httpClient;
62
63
64
    private $oAuth2Token = '';
65
    private $oAuth2TokenExpires = '';
66
67
    public function __construct($baseUrl, $instanceName, $config)
68
    {
69
        $this->baseUrl = $baseUrl;
70
        $this->instanceName = $instanceName;
71
        $this->config = $config;
72
    }
73
74
75
    /**
76
     * get instance name of the cart
77
     *
78
     * @return string
79
     */
80
    public function getInstanceName()
81
    {
82
        return $this->instanceName;
83
    }
84
85
86
    private function withBasicAuth()
87
    {
88
        $this->httpClient = Http::withBasicAuth($this->config['api_key'], $this->config['secret_key'])->asJson();
0 ignored issues
show
Documentation Bug introduced by
It seems like Illuminate\Support\Facad...secret_key'])->asJson() of type Illuminate\Http\Client\PendingRequest is incompatible with the declared type Illuminate\Support\Facades\Http of property $httpClient.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
89
        return $this;
90
    }
91
92
93
    /**
94
     * @return $this
95
     * @throws MonnifyFailedRequestException
96
     */
97
    private function getToken()
98
    {
99
        $endpoint = "{$this->baseUrl}{$this->v1}auth/login";
100
        $this->withBasicAuth();
101
        $response = $this->httpClient->post($endpoint);
102
103
        $responseObject = json_decode($response->body());
104
        if (!$response->successful())
105
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
106
107
        $this->oAuth2Token = $responseObject->responseBody->accessToken;
108
        $this->oAuth2TokenExpires = ((time() + $responseObject->responseBody->expiresIn) - 60);//Just make sure the token would not expire in 60 secs
109
110
        return $this;
111
    }
112
113
114
    private function withOAuth2()
115
    {
116
        if (time() >= $this->oAuth2TokenExpires) {
117
            $this->getToken();
118
            $this->httpClient = Http::withToken($this->oAuth2Token);
0 ignored issues
show
Documentation Bug introduced by
It seems like Illuminate\Support\Facad...ken($this->oAuth2Token) of type Illuminate\Http\Client\PendingRequest is incompatible with the declared type Illuminate\Support\Facades\Http of property $httpClient.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
119
        }
120
121
        return $this;
122
    }
123
124
125
    /**
126
     * This enables you to retrieve all banks supported by Monnify for collections and disbursements.
127
     * @return array
128
     *
129
     * @throws MonnifyFailedRequestException
130
     */
131
    public function getBanks()
132
    {
133
        $endpoint = "{$this->baseUrl}{$this->v1}banks";
134
135
        $this->withOAuth2();
136
        $response = $this->httpClient->get($endpoint);
137
138
        $responseObject = json_decode($response->body());
139
        if (!$response->successful())
140
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
141
142
        return $responseObject->responseBody;
143
    }
144
145
146
    /**
147
     * This API enables you to retrieve all banks with valid USSD short code. This is useful if you'll like to display USSD short codes for your customers to dial.
148
     * For a full list of banks, use @return array
149
     *
150
     * @throws MonnifyFailedRequestException
151
     *
152
     * @see getBanks()
153
     *
154
     */
155
    public function getBanksWithUSSDShortCode()
156
    {
157
        $endpoint = "{$this->baseUrl}{$this->v1}sdk/transactions/banks";
158
159
        $this->withOAuth2();
160
        $response = $this->httpClient->get($endpoint);
161
162
        $responseObject = json_decode($response->body());
163
        if (!$response->successful())
164
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
165
166
        return $responseObject->responseBody;
167
    }
168
169
170
    /**
171
     * Creates a sub account for a merchant. Allowing the merchant split transaction settlement between the main account and one or more sub account(s)
172
     * For $bankCode, check returned object from getBanks() or  getBanksWithUSSDShortCode()
173
     * @param string $bankCode
174
     * @param string $accountNumber The account number that should be created as a sub account.
175
     * @param string $email The email tied to the sub account. This email will receive settlement reports for settlements into the sub account.
176
     * @param string|null $currencyCode
177
     * @param string|null $splitPercentage
178
     * @return array
179
     *
180
     * @throws MonnifyFailedRequestException
181
     *
182
     * Once the request is sent, a sub account code will be returned. This sub account code is the unique identifier for that sub account and will be used to reference the sub account in split payment requests.
183
     * <strong>Note: </strong> Currency code and Split Percentage will use the configured default in you .env file if not explicitly provided
184
     * Also, if bank account is not found within the provide bank code a MonnifyFailedRequestException will be thrown
185
     *
186
     */
187
    public function createSubAccount(string $bankCode, string $accountNumber, string $email, string $currencyCode = null, string $splitPercentage = null)
188
    {
189
        $currencyCode = $currencyCode ?? $this->config['default_currency_code'];
190
        $splitPercentage = $splitPercentage ?? $this->config['default_split_percentage'];
191
192
        $endpoint = "{$this->baseUrl}{$this->v1}sub-accounts";
193
194
        $this->withBasicAuth();
195
        $response = $this->httpClient->post($endpoint, [[
196
            'currencyCode' => $currencyCode,
197
            'bankCode' => $bankCode,
198
            'accountNumber' => $accountNumber,
199
            'email' => $email,
200
            'defaultSplitPercentage' => $splitPercentage,
201
        ],]);
202
203
        $responseObject = json_decode($response->body());
204
        if (!$response->successful())
205
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
206
207
        return $responseObject->responseBody;
208
    }
209
210
211
    /**
212
     * Creates a sub accounts for a merchant. Allowing the merchant split transaction settlement between the main account and one or more sub account(s)
213
     * For $bankCode, check returned object from getBanks() or  getBanksWithUSSDShortCode()
214
     * @param array $accounts is an array of arrays, with each individual array containing the following keys 'currencyCode', 'bankCode', 'accountNumber', 'email', and 'defaultSplitPercentage'
215
     * Note that you can always get the set default currency code as well as default split percentage from the monnify config file with config('monnify.default_currency_code') and config('monnify.default_split_percentage') respectively
216
     * @return array
217
     *
218
     * @throws MonnifyFailedRequestException
219
     *
220
     * Once the request is sent, a sub account code will be returned. This sub account code is the unique identifier for that sub account and will be used to reference the sub account in split payment requests.
221
     * <strong>Note: </strong> If any of the provided details bank account is not found within the corresponding provide bank code a MonnifyFailedRequestException will be thrown
222
     *
223
     */
224
    public function createSubAccounts(array $accounts)
225
    {
226
        $endpoint = "{$this->baseUrl}{$this->v1}sub-accounts";
227
228
        $this->withBasicAuth();
229
        $response = $this->httpClient->post($endpoint, $accounts);
230
231
        $responseObject = json_decode($response->body());
232
        if (!$response->successful())
233
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
234
235
        return $responseObject->responseBody;
236
    }
237
238
239
    /**
240
     * Returns a list of sub accounts previously created by the merchant.
241
     * @return array
242
     *
243
     * @throws MonnifyFailedRequestException
244
     *
245
     */
246
    public function getSubAccounts()
247
    {
248
        $endpoint = "{$this->baseUrl}{$this->v1}sub-accounts";
249
250
        $this->withBasicAuth();
251
        $response = $this->httpClient->get($endpoint);
252
253
        $responseObject = json_decode($response->body());
254
        if (!$response->successful())
255
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
256
257
        return $responseObject->responseBody;
258
    }
259
260
261
    /**
262
     * Deletes a merchant's sub account.
263
     * @param string $subAccountCode The unique reference for the sub account
264
     * @return array
265
     *
266
     * @throws MonnifyFailedRequestException
267
     */
268
    public function deleteSubAccount(string $subAccountCode)
269
    {
270
        $endpoint = "{$this->baseUrl}{$this->v1}sub-accounts/$subAccountCode";
271
272
        $this->withBasicAuth();
273
        $response = $this->httpClient->delete($endpoint);
274
275
        $responseObject = json_decode($response->body());
276
        if (!$response->successful())
277
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
278
279
        return $responseObject->responseMessage;
280
    }
281
282
283
    /**
284
     * Updates the information on an existing sub account for a merchant.
285
     *
286
     * @param string $subAccountCode The unique reference for the sub account
287
     * @param string $bankCode
288
     * @param string $accountNumber
289
     * @param string $email The email tied to the sub account. This email will receive settlement reports for settlements into the sub account.
290
     * @param string|null $currencyCode
291
     * @param string|null $splitPercentage
292
     * @return array
293
     *
294
     * @throws MonnifyFailedRequestException
295
     *
296
     */
297
    public function updateSubAccount(string $subAccountCode, string $bankCode, string $accountNumber, string $email, string $currencyCode = null, string $splitPercentage = null)
298
    {
299
        $currencyCode = $currencyCode ?? $this->config['default_currency_code'];
300
        $splitPercentage = $splitPercentage ?? $this->config['default_split_percentage'];
301
302
        $endpoint = "{$this->baseUrl}{$this->v1}sub-accounts";
303
304
        $this->withBasicAuth();
305
        $response = $this->httpClient->put($endpoint, [
306
            'subAccountCode' => $subAccountCode,
307
            'currencyCode' => $currencyCode,
308
            'bankCode' => $bankCode,
309
            'accountNumber' => $accountNumber,
310
            'email' => $email,
311
            'defaultSplitPercentage' => $splitPercentage,
312
        ]);
313
314
        $responseObject = json_decode($response->body());
315
        if (!$response->successful())
316
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
317
318
        return $responseObject->responseBody;
319
    }
320
321
322
    /**
323
     * This returns all transactions done by a merchant.
324
     *
325
     * @param array $queryParams
326
     * @return object
327
     *
328
     * @throws MonnifyFailedRequestException
329
     *
330
     * Kindly check here for query parameters keys
331
     * @link https://docs.teamapt.com/display/MON/Get+All+Transactions
332
     */
333
    public function getAllTransactions(array $queryParams)
334
    {
335
        $endpoint = "{$this->baseUrl}{$this->v1}transactions/search?" . http_build_query($queryParams, '', '&amp;');
336
337
        $this->withOAuth2();
338
        $response = $this->httpClient->get($endpoint);
339
340
        $responseObject = json_decode($response->body());
341
        if (!$response->successful())
342
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
343
344
        return $responseObject->responseBody;
345
    }
346
347
348
    /**
349
     * Once an account number has been reserved for a customer, the customer can make payment by initiating a transfer to that account number at any time. Once the transfer hits the partner bank, we will notify you with the transfer details along with the accountReference you specified when reserving the account.
350
     *
351
     * @param string $accountReference Your unique reference used to identify this reserved account
352
     * @param string $accountName The name you want to be attached to the reserved account. This will be displayed during name enquiry
353
     * @param string $customerEmail Email address of the customer who the account is being reserved for. This is the unique identifier for each customer.
354
     * @param string $customerName Full name of the customer who the account is being reserved for
355
     * @param string|null $customerBvn BVN of the customer the account is being reserved for. Although this field is not mandated, it is advised that it is supplied. Please note that there could be low limits on the reserved account in future, if BVN is not supplied.
356
     * @param string|null $currencyCode
357
     * @param MonnifyIncomeSplitConfig|null $incomeSplitConfig
358
     * @param bool $restrictPaymentSource
359
     * @param MonnifyAllowedPaymentSources $allowedPaymentSources
360
     * @return object
361
     *
362
     * @throws MonnifyInvalidParameterException
363
     * @throws MonnifyFailedRequestException
364
     * @link https://docs.teamapt.com/display/MON/Reserving+An+Account
365
     */
366
    public function reserveAccount(string $accountReference, string $accountName, string $customerEmail, string $customerName = null, string $customerBvn = null, string $currencyCode = null, bool $restrictPaymentSource = false, MonnifyAllowedPaymentSources $allowedPaymentSources = null, MonnifyIncomeSplitConfig $incomeSplitConfig = null)
367
    {
368
        if ($restrictPaymentSource && is_null($allowedPaymentSources))
369
            throw new MonnifyInvalidParameterException("Allowed Payment Sources can't be null if payment source is restricted");
370
371
        $endpoint = "{$this->baseUrl}{$this->v1}bank-transfer/reserved-accounts";
372
        $requestBody = [
373
            "accountReference" => $accountReference,
374
            "accountName" => $accountName,
375
            "currencyCode" => $currencyCode ?? $this->config['default_currency_code'],
376
            "contractCode" => $this->config['contract_code'],
377
            "customerEmail" => $customerEmail,
378
            "restrictPaymentSource" => $restrictPaymentSource,
379
        ];
380
381
        if ((!is_null($customerName)) && (!empty(trim($customerName))))
382
            $requestBody['customerName'] = $customerName;
383
384
        if ((!is_null($customerBvn)) && (!empty(trim($customerBvn))))
385
            $requestBody['customerBvn'] = $customerBvn;
386
387
        if (!is_null($allowedPaymentSources))
388
            $requestBody['allowedPaymentSources'] = $allowedPaymentSources->toArray();
389
390
        if (!is_null($incomeSplitConfig))
391
            $requestBody['incomeSplitConfig'] = $incomeSplitConfig->toArray();
392
393
        $this->withOAuth2();
394
        $response = $this->httpClient->post($endpoint, $requestBody);
395
396
397
        $responseObject = json_decode($response->body());
398
        if (!$response->successful())
399
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
400
401
        return $responseObject->responseBody;
402
    }
403
404
405
    /**
406
     * If you want to get the details of a reserved account, you can initiate a GET request to the endpoint below and we will return all the details attached to that account Reference.
407
     *
408
     * @param string $accountReference Your unique reference used to identify this reserved account
409
     * @return object
410
     *
411
     * @throws MonnifyFailedRequestException
412
     * @link https://docs.teamapt.com/display/MON/Get+Reserved+Account+Details
413
     */
414
    public function getReservedAccountDetails(string $accountReference)
415
    {
416
        $endpoint = "{$this->baseUrl}{$this->v1}bank-transfer/reserved-accounts/$accountReference";
417
418
        $this->withOAuth2();
419
        $response = $this->httpClient->get($endpoint);
420
421
422
        $responseObject = json_decode($response->body());
423
        if (!$response->successful())
424
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
425
426
        return $responseObject->responseBody;
427
    }
428
429
430
    /**
431
     * You can update income splitting config for a reserved account using the endpoint below.
432
     *
433
     * @param string $accountReference Your unique reference used to identify this reserved account
434
     * @param MonnifyIncomeSplitConfig $incomeSplitConfig
435
     * @return object
436
     *
437
     * @throws MonnifyFailedRequestException
438
     * @link https://docs.teamapt.com/display/MON/Updating+Split+Config+for+Reserved+Account
439
     */
440
    public function updateReservedAccountSplitConfig(string $accountReference, MonnifyIncomeSplitConfig $incomeSplitConfig)
441
    {
442
        $endpoint = "{$this->baseUrl}{$this->v1}bank-transfer/reserved-accounts/update-income-split-config/$accountReference";
443
444
        $this->withOAuth2();
445
        $response = $this->httpClient->put($endpoint, $incomeSplitConfig->toArray());
446
447
448
        $responseObject = json_decode($response->body());
449
        if (!$response->successful())
450
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
451
452
        return $responseObject->responseBody;
453
    }
454
455
456
    /**
457
     * You can get a paginated list of transactions processed to a reserved account by making a GET Request to the endpoint below and by specifying the accountReference as a query parameter. You can also specify the page number and size (number of transactions) you want returned per page.
458
     *
459
     * @param string $accountReference Your unique reference used to identify this reserved account
460
     * @param int $page The page of data you want returned by Monnify (Starts from 0)
461
     * @param int $size The number of records you want returned in a page.
462
     * @return object
463
     *
464
     * @throws MonnifyFailedRequestException
465
     * @link https://docs.teamapt.com/display/MON/Getting+all+transactions+on+a+reserved+account
466
     */
467
    public function getAllTransactionsForReservedAccount(string $accountReference, int $page = 0, int $size = 10)
468
    {
469
        $endpoint = "{$this->baseUrl}{$this->v1}bank-transfer/reserved-accounts/transactions?accountReference=$accountReference&page=$page&size=$size";
470
471
        $this->withOAuth2();
472
        $response = $this->httpClient->get($endpoint);
473
474
475
        $responseObject = json_decode($response->body());
476
        if (!$response->successful())
477
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
478
479
        return $responseObject->responseBody;
480
    }
481
482
483
    /**
484
     * You can delete a reserved account by initiating a DELETE request to the endpoint below. We will immediately deallocate the account.
485
     * Please note this action cannot be reversed!!
486
     *
487
     * @param string $accountNumber The virtual account number generated for the accountReference (Reserved account number)
488
     * @return object
489
     *
490
     * @throws MonnifyFailedRequestException
491
     * @link https://docs.teamapt.com/display/MON/Deallocating+a+reserved+account
492
     */
493
    public function deallocateReservedAccount(string $accountNumber)
494
    {
495
        $endpoint = "{$this->baseUrl}{$this->v1}bank-transfer/reserved-accounts/$accountNumber";
496
497
        $this->withOAuth2();
498
        $response = $this->httpClient->delete($endpoint);
499
500
501
        $responseObject = json_decode($response->body());
502
        if (!$response->successful())
503
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
504
505
        return $responseObject->responseBody;
506
    }
507
508
509
    /**
510
     * This API enables you restrict accounts that can fund a reserved account. This most used for a wallet system where you want only the owner of a reserved account to fund the reserved account.
511
     *
512
     * You can explicitly specify account numbers, or specify one or more account names.
513
     *
514
     * <strong>How are specified rules applied?</strong>
515
     * If only account numbers are specified, funding of account will be restricted to specified account numbers.
516
     * If only account names are specified, funding of account will be restricted to specified account names.
517
     * If both account numbers and account names are specified, funding will be permitted when either of the two rules match, i.e. source account number matches specified account numbers or source account name matches specified account name.
518
     * Account Name Matching Rule
519
     *
520
     * Matching of source account name is dynamic, such that if CIROMA CHUKWUMA ADEKUNLE is the specified account name, funding of accounts will be permitted from accounts with name that has AT LEAST TWO words from the specified name, and in any order.
521
     *
522
     * @param string $accountReference Your unique reference used to identify this reserved account
523
     * @param MonnifyAllowedPaymentSources $allowedPaymentSources
524
     * @return object
525
     *
526
     * @throws MonnifyFailedRequestException
527
     * @link https://docs.teamapt.com/display/MON/Getting+all+transactions+on+a+reserved+account
528
     */
529
    public function sourceAccountRestriction(string $accountReference, MonnifyAllowedPaymentSources $allowedPaymentSources)
530
    {
531
        $endpoint = "{$this->baseUrl}{$this->v1}bank-transfer/reserved-accounts/update-payment-source-filter/$accountReference";
532
533
        $this->withOAuth2();
534
        $response = $this->httpClient->put($endpoint, [
535
            "restrictPaymentSource" => true,
536
            "allowedPaymentSources" => $allowedPaymentSources->toArray()
537
        ]);
538
539
540
        $responseObject = json_decode($response->body());
541
        if (!$response->successful())
542
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
543
544
        return $responseObject->responseBody;
545
    }
546
547
548
    /**
549
     * Allows you initialize a transaction on Monnify and returns a checkout URL which you can load within a browser to display the payment form to your customer.
550
     *
551
     * @param float $amount The amount to be paid by the customer
552
     * @param string $customerName Full name of the customer
553
     * @param string $customerEmail Email address of the customer
554
     * @param string $paymentReference Merchant's Unique reference for the transaction.
555
     * @param string $paymentDescription Description for the transaction. Will be returned as part of the account name on name enquiry for transfer payments.
556
     * @param string $redirectUrl A URL which user will be redirected to, on completion of the payment.
557
     * @param MonnifyPaymentMethods $monnifyPaymentMethods
558
     * @param MonnifyIncomeSplitConfig $incomeSplitConfig
559
     * @param string|null $currencyCode
560
     * @return array
561
     *
562
     * @throws MonnifyFailedRequestException
563
     * @link https://docs.teamapt.com/display/MON/Initialize+Transaction
564
     */
565
    public function initializeTransaction(float $amount, string $customerName, string $customerEmail, string $paymentReference, string $paymentDescription, string $redirectUrl, MonnifyPaymentMethods $monnifyPaymentMethods, MonnifyIncomeSplitConfig $incomeSplitConfig = null, string $currencyCode = null)
566
    {
567
        $endpoint = "{$this->baseUrl}{$this->v1}merchant/transactions/init-transaction";
568
569
        $this->withBasicAuth();
570
        $formData = [
571
            "amount" => $amount,
572
            "customerName" => trim($customerName),
573
            "customerEmail" => $customerEmail,
574
            "paymentReference" => $paymentReference,
575
            "paymentDescription" => trim($paymentDescription),
576
            "currencyCode" => $currencyCode ?? $this->config['default_currency_code'],
577
            "contractCode" => $this->config['contract_code'],
578
            "redirectUrl" => trim($redirectUrl),
579
            "paymentMethods" => $monnifyPaymentMethods->toArray(),
580
        ];
581
        if ($incomeSplitConfig !== null)
582
            $formData["incomeSplitConfig"] = $incomeSplitConfig->toArray();
583
584
        $response = $this->httpClient->post($endpoint, $formData);
585
586
        $responseObject = json_decode($response->body());
587
        if (!$response->successful())
588
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
589
590
        return $responseObject->responseBody;
591
    }
592
593
594
    /**
595
     * When Monnify sends transaction notifications, we add a transaction hash for security reasons. We expect you to try to recreate the transaction hash and only honor the notification if it matches.
596
     *
597
     * To calculate the hash value, concatenate the following parameters in the request body and generate a hash using the SHA512 algorithm:
598
     *
599
     * @param string $paymentReference Unique reference generated by the merchant for each transaction. However, will be the same as transactionReference for reserved accounts.
600
     * @param mixed $amountPaid The amount that was paid by the customer
601
     * @param string $paidOn Date and Time when payment happened in the format dd/mm/yyyy hh:mm:ss
602
     * @param string $transactionReference Unique transaction reference generated by Monnify for each transaction
603
     * @return string Hash of successful transaction
604
     *
605
     * @link https://docs.teamapt.com/display/MON/Calculating+the+Transaction+Hash
606
     */
607
    public function calculateTransactionHash(string $paymentReference, $amountPaid, string $paidOn, string $transactionReference)
608
    {
609
        $clientSK = $this->config['secret_key'];
610
        return hash('sha512', "$clientSK|$paymentReference|$amountPaid|$paidOn|$transactionReference");
611
    }
612
613
    public function calculateTransactionHashFix(string $paymentReference, $amountPaid, string $paidOn, string $transactionReference)
614
    {
615
        $clientSK = $this->config['secret_key'];
616
        return hash('sha512', "$clientSK|$paymentReference|$amountPaid|$paidOn|$transactionReference");
617
    }
618
619
620
    /**
621
     * We highly recommend that when you receive a notification from us, even after checking to ensure the hash values match,
622
     * you should initiate a get transaction status request to us with the transactionReference to confirm the actual status of that transaction before updating the records on your database.
623
     *
624
     * @param string $transactions Unique transaction reference generated by Monnify for each transaction
625
     * @return object
626
     *
627
     * @throws MonnifyFailedRequestException
628
     * @link https://docs.teamapt.com/display/MON/Get+Transaction+Status
629
     */
630
    public function getTransactionStatus(string $transactions)
631
    {
632
        $endpoint = "{$this->baseUrl}{$this->v2}transactions/$transactions/";
633
634
        $this->withOAuth2();
635
        $response = $this->httpClient->get($endpoint);
636
637
        $responseObject = json_decode($response->body());
638
        if (!$response->successful())
639
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
640
641
        return $responseObject->responseBody;
642
    }
643
644
645
    /**
646
     * Allows you get virtual account details for a transaction using the transactionReference of an initialized transaction.
647
     * This is useful if you want to control the payment interface.
648
     * There are a lot of UX considerations to keep in mind if you choose to do this so we recommend you read this @link https://docs.teamapt.com/display/MON/Optimizing+Your+User+Experience.
649
     *
650
     * @param string $transactionReference
651
     * @param string $bankCode
652
     * @return array
653
     *
654
     * @throws MonnifyFailedRequestException
655
     * @link https://docs.teamapt.com/display/MON/Pay+with+Bank+Transfer
656
     */
657
    public function payWithBankTransfer(string $transactionReference, string $bankCode)
658
    {
659
        $endpoint = "{$this->baseUrl}{$this->v1}merchant/bank-transfer/init-payment";
660
661
        $this->withBasicAuth();
662
        $response = $this->httpClient->post($endpoint, [
663
            "transactionReference" => $transactionReference,
664
            "bankCode" => trim($bankCode),
665
        ]);
666
667
        $responseObject = json_decode($response->body());
668
        if (!$response->successful())
669
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
670
671
        return $responseObject->responseBody;
672
    }
673
674
675
    /**
676
     * To initiate a single transfer,  you will need to send a request to the endpoint below:
677
     *
678
     * If the merchant does not have Two Factor Authentication (2FA) enabled, the transaction will be processed instantly and the response will be as follows:
679
     *
680
     * If the merchant has Two Factor Authentication (2FA) enabled, a One Time Password (OTP) will be sent to the designated email address(es). That OTP will need to be supplied via the VALIDATE OTP REQUEST before the transaction can be approved. If 2FA is enabled,
681
     *
682
     * @param float $amount
683
     * @param string $reference
684
     * @param string $narration
685
     * @param MonnifyBankAccount $bankAccount
686
     * @param string|null $currencyCode
687
     * @return array
688
     *
689
     * @throws MonnifyFailedRequestException
690
     *
691
     * @see https://docs.teamapt.com/display/MON/Initiate+Transfer
692
     */
693
    public function initiateTransferSingle(float $amount, string $reference, string $narration, MonnifyBankAccount $bankAccount, string $currencyCode = null)
694
    {
695
        $endpoint = "{$this->baseUrl}{$this->v1}disbursements/single";
696
697
        $this->withBasicAuth();
698
        $response = $this->httpClient->post($endpoint, [
699
            "amount" => $amount,
700
            "reference" => trim($reference),
701
            "narration" => trim($narration),
702
            "bankCode" => $bankAccount->getBankCode(),
703
            "accountNumber" => $bankAccount->getAccountNumber(),
704
            "currency" => $currencyCode ?? $this->config['default_currency_code'],
705
            "walletId" => $this->config['wallet_id']
706
        ]);
707
708
        $responseObject = json_decode($response->body());
709
        if (!$response->successful())
710
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
711
712
        return $responseObject->initiateTransferSingle;
713
    }
714
715
716
    /**
717
     * To initiate a single transfer,  you will need to send a request to the endpoint below:
718
     *
719
     * If the merchant does not have Two Factor Authentication (2FA) enabled, the transaction will be processed instantly and the response will be as follows:
720
     *
721
     * If the merchant has Two Factor Authentication (2FA) enabled, a One Time Password (OTP) will be sent to the designated email address(es). That OTP will need to be supplied via the VALIDATE OTP REQUEST before the transaction can be approved. If 2FA is enabled,
722
     *
723
     *
724
     * @param MonnifyTransaction $monnifyTransaction Transaction Object
725
     * @return array
726
     *
727
     * @throws MonnifyFailedRequestException
728
     * @see https://docs.teamapt.com/display/MON/Initiate+Transfer
729
     */
730
    public function initiateTransferSingleWithMonnifyTransaction(MonnifyTransaction $monnifyTransaction)
731
    {
732
        return $this->initiateTransferSingle($monnifyTransaction->getAmount(), $monnifyTransaction->getReference(), $monnifyTransaction->getNarration(), $monnifyTransaction->getBankAccount(), $monnifyTransaction->getCurrencyCode());
733
    }
734
735
736
    /**
737
     * To initiate a single transfer,  you will need to send a request to the endpoint below:
738
     * Bulk transfers allows you send a single request with a list of disbursements you want to be processed. Below is a sample request for initiating a bulk transfer
739
     *
740
     * If the merchant does not have Two Factor Authentication (2FA) enabled, the transaction will be processed instantly and the response will be as follows:
741
     *
742
     * If the merchant has Two Factor Authentication (2FA) enabled, a One Time Password (OTP) will be sent to the designated email address(es). That OTP will need to be supplied via the VALIDATE OTP REQUEST before the transaction can be approved. If 2FA is enabled,
743
     *
744
     * @param string $title
745
     * @param string $batchReference The unique reference for the entire batch of transactions being sent.
746
     * @param string $narration The Narration for the transactions being processed
747
     * @param MonnifyOnFailureValidate $onFailureValidate Used to determine how Monnify should handle failed transaction validations in a batch. The two options are MonnifyOnFailureValidate::BREAK() & MonnifyOnFailureValidate::CONTINUE(). Use MonnifyOnFailureValidate::BREAK() to tell Monnify to reject the entire batch and use MonnifyOnFailureValidate::CONTINUE() to tell Monnify to process the valid transactions.
748
     * @param int $notificationInterval Used to determine how often Monnify should notify the merchant of progress when processing a batch transfer. The options are 10, 20, 50 and 100 and they represent percentages. i.e. 20 means notify me at intervals of 20% (20%, 40%, 60%, 80% ,100%).
749
     * @param MonnifyTransactionList $transactionList
750
     * @return array
751
     *
752
     * @throws MonnifyFailedRequestException
753
     * @see https://docs.teamapt.com/display/MON/Initiate+Transfer
754
     */
755
    public function initiateTransferBulk(string $title, string $batchReference, string $narration, MonnifyOnFailureValidate $onFailureValidate, int $notificationInterval, MonnifyTransactionList $transactionList)
756
    {
757
        $endpoint = "{$this->baseUrl}{$this->v1}disbursements/batch";
758
759
        $this->withBasicAuth();
760
        $response = $this->httpClient->post($endpoint, [
761
            "title" => $title,
762
            "batchReference" => trim($batchReference),
763
            "narration" => trim($narration),
764
            "walletId" => $this->config['wallet_id'],
765
            "onValidationFailure" => "$onFailureValidate",
766
            "notificationInterval" => $notificationInterval,
767
            "transactionList" => $transactionList->toArray()
768
        ]);
769
770
        $responseObject = json_decode($response->body());
771
        if (!$response->successful())
772
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
773
774
        return $responseObject->responseBody;
775
    }
776
777
    /**
778
     * @param string $authorizationCode The One Time Password sent to the specified email to be used to authenticate the transaction
779
     * @param string $reference The unique reference for a transaction. Also to be specified for each transaction in a bulk transaction request.
780
     * @param string $path
781
     * @return object
782
     *
783
     * @throws MonnifyFailedRequestException
784
     * @link https://docs.teamapt.com/pages/viewpage.action?pageId=4587995
785
     */
786
    private function authorizeTransfer2FA(string $authorizationCode, string $reference, string $path)
787
    {
788
        $endpoint = "{$this->baseUrl}{$this->v1}disbursements/$path/validate-otp";
789
790
        $this->withBasicAuth();
791
        $response = $this->httpClient->post($endpoint, [
792
            "authorizationCode" => $authorizationCode,
793
            "reference" => trim($reference),
794
        ]);
795
796
        $responseObject = json_decode($response->body());
797
        if (!$response->successful())
798
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
799
800
        return $responseObject->responseBody;
801
    }
802
803
    /**
804
     * To authorize a single transfer, you will need to send a request to using this
805
     *
806
     * @param string $authorizationCode The One Time Password sent to the specified email to be used to authenticate the transaction
807
     * @param string $reference The unique reference for a transaction. Also to be specified for each transaction in a bulk transaction request.
808
     * @return object
809
     *
810
     * @throws MonnifyFailedRequestException
811
     * @link https://docs.teamapt.com/pages/viewpage.action?pageId=4587995
812
     */
813
    public function authorizeSingleTransfer2FA(string $authorizationCode, string $reference)
814
    {
815
        return $this->authorizeTransfer2FA($authorizationCode, $reference, 'single');
816
    }
817
818
    /**
819
     * To authorize a bulk transfer, you will need to send a request to using this
820
     *
821
     * @param string $authorizationCode The One Time Password sent to the specified email to be used to authenticate the transaction
822
     * @param string $reference The unique reference for a transaction. Also to be specified for each transaction in a bulk transaction request.
823
     * @return object
824
     *
825
     * @throws MonnifyFailedRequestException
826
     * @link https://docs.teamapt.com/pages/viewpage.action?pageId=4587995
827
     */
828
    public function authorizeBulkTransfer2FA(string $authorizationCode, string $reference)
829
    {
830
        return $this->authorizeTransfer2FA($authorizationCode, $reference, 'batch');
831
    }
832
833
834
    /**
835
     * @param string $reference The unique reference for a transaction. Also to be specified for each transaction in a bulk transaction request.
836
     * @param string $path
837
     * @return object
838
     *
839
     * @throws MonnifyFailedRequestException
840
     * @link https://docs.teamapt.com/display/MON/Get+Transfer+Details
841
     */
842
    private function getTransferDetails(string $reference, string $path)
843
    {
844
        $endpoint = "{$this->baseUrl}{$this->v1}disbursements/$path/summary?reference=$reference";
845
846
        $this->withBasicAuth();
847
        $response = $this->httpClient->get($endpoint);
848
849
        $responseObject = json_decode($response->body());
850
        if (!$response->successful())
851
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
852
853
        return $responseObject->responseBody;
854
    }
855
856
857
    /**
858
     * Single Transfers
859
     * To get the details of a single transfer
860
     *
861
     * @param string $reference The unique reference for a transaction. Also to be specified for each transaction in a bulk transaction request.
862
     * @return object
863
     *
864
     * @throws MonnifyFailedRequestException
865
     * @link https://docs.teamapt.com/display/MON/Get+Transfer+Details
866
     */
867
    public function getSingleTransferDetails(string $reference)
868
    {
869
        return $this->getTransferDetails($reference, 'single');
870
    }
871
872
873
    /**
874
     * Bulk Transfers
875
     * To get the details of a bulk transfer
876
     *
877
     * @param string $batchReference The unique reference for a transaction. Also to be specified for each transaction in a bulk transaction request.
878
     * @return object
879
     *
880
     * @throws MonnifyFailedRequestException
881
     * @link https://docs.teamapt.com/display/MON/Get+Transfer+Details
882
     */
883
    public function getBulkTransferDetails(string $batchReference)
884
    {
885
        return $this->getTransferDetails($batchReference, 'batch');
886
    }
887
888
889
    /**
890
     * This allows you get a paginated list of all transactions in a bulk transfer batch and their statuses.
891
     *
892
     * @param string $batchReference The unique reference for the entire batch of transactions being sent.
893
     * @param int $pageNo A number specifying what page of transfers to be retrieved. Minimum value is 0, and defaults to 0 if not specified.
894
     * @param int $pageSize A number specifying size of each transfer page. Minimum value is 1, and defaults to 10 if not specified.
895
     * @return object
896
     *
897
     * @throws MonnifyFailedRequestException
898
     * @link https://docs.teamapt.com/display/MON/Get+Bulk+Transfer+Transactions
899
     */
900
    public function getBulkTransferTransactions(string $batchReference, int $pageNo = 0, int $pageSize = 10)
901
    {
902
        $endpoint = "{$this->baseUrl}{$this->v1}disbursements/bulk/$batchReference/transactions?pageNo=$pageNo&pageSize=$pageSize";
903
        $this->withBasicAuth();
904
        $response = $this->httpClient->get($endpoint);
905
906
        $responseObject = json_decode($response->body());
907
        if (!$response->successful())
908
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
909
910
        return $responseObject->responseBody;
911
    }
912
913
914
    /**
915
     * This allows you get a paginated list of all transactions in a bulk transfer batch and their statuses.
916
     *
917
     * @param string $path
918
     * @param int $pageNo A number specifying what page of transfers to be retrieved. Minimum value is 0, and defaults to 0 if not specified.
919
     * @param int $pageSize A number specifying size of each transfer page. Minimum value is 1, and defaults to 10 if not specified.
920
     * @return object
921
     *
922
     * @throws MonnifyFailedRequestException
923
     * @link https://docs.teamapt.com/display/MON/List+All+Transfers
924
     */
925
    private function listAllTransfers(string $path, int $pageNo = 0, int $pageSize = 10)
926
    {
927
        $endpoint = "{$this->baseUrl}{$this->v1}disbursements/$path/transactions?pageNo=$pageNo&pageSize=$pageSize";
928
929
        $this->withBasicAuth();
930
        $response = $this->httpClient->get($endpoint);
931
932
        $responseObject = json_decode($response->body());
933
        if (!$response->successful())
934
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
935
936
        return $responseObject->responseBody;
937
    }
938
939
940
    /**
941
     * Single Transfers
942
     * To get a list of all single transfers
943
     *
944
     * @param int $pageNo
945
     * @param int $pageSize
946
     * @return object
947
     *
948
     * @throws MonnifyFailedRequestException
949
     * @link https://docs.teamapt.com/display/MON/Get+Transfer+Details
950
     */
951
    public function getSingleTransferTransactions(int $pageNo = 0, int $pageSize = 10)
952
    {
953
        return $this->listAllTransfers('single', $pageNo, $pageSize);
954
    }
955
956
957
    /**
958
     * Bulk Transfers
959
     * To get a list of all bulk transfers
960
     *
961
     * @param int $pageNo
962
     * @param int $pageSize
963
     * @return object
964
     *
965
     * @throws MonnifyFailedRequestException
966
     * @link https://docs.teamapt.com/display/MON/Get+Transfer+Details
967
     */
968
    public function getAllBulkTransferTransactions(int $pageNo = 0, int $pageSize = 10)
969
    {
970
        return $this->listAllTransfers('bulk', $pageNo, $pageSize);
971
    }
972
973
974
    /**
975
     * This allows you check if an account number is a valid NUBAN, get the account name if valid.
976
     *
977
     * @param MonnifyBankAccount $bankAccount
978
     * @return mixed
979
     * @throws MonnifyFailedRequestException
980
     *
981
     * @link https://docs.teamapt.com/display/MON/Validate+Bank+Account
982
     */
983
    public function validateBankAccount(MonnifyBankAccount $bankAccount)
984
    {
985
986
        $endpoint = "{$this->baseUrl}{$this->v1}disbursements/account/validate?accountNumber={$bankAccount->getAccountNumber()}&bankCode={$bankAccount->getBankCode()}";
987
        $this->withBasicAuth();
988
        $response = $this->httpClient->get($endpoint);
989
990
        $responseObject = json_decode($response->body());
991
        if (!$response->successful())
992
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
993
994
        return $responseObject->responseBody;
995
    }
996
997
998
    /**
999
     * This allows you to get the available balance in your monnify wallet.
1000
     *
1001
     * @return mixed
1002
     * @throws MonnifyFailedRequestException
1003
     *
1004
     * @link https://docs.teamapt.com/display/MON/Get+Wallet+Balance
1005
     */
1006
    public function getWalletBalance()
1007
    {
1008
        $endpoint = "{$this->baseUrl}{$this->v1}disbursements/wallet-balance?walletId={$this->config['wallet_id']}";
1009
        $this->withBasicAuth();
1010
        $response = $this->httpClient->get($endpoint);
1011
1012
        $responseObject = json_decode($response->body());
1013
        if (!$response->successful())
1014
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
1015
1016
        return $responseObject->responseBody;
1017
    }
1018
1019
1020
    /**
1021
     * This allows you to resend OTP for 2FA
1022
     *
1023
     * @param string $reference
1024
     * @return mixed
1025
     * @throws MonnifyFailedRequestException
1026
     * @link https://docs.teamapt.com/display/MON/Resend+OTP
1027
     */
1028
    public function resendOTP(string $reference)
1029
    {
1030
        $endpoint = "{$this->baseUrl}{$this->v1}disbursements/single/resend-otp";
1031
        $this->withBasicAuth();
1032
        $response = $this->httpClient->post($endpoint, [
1033
            'reference' => $reference
1034
        ]);
1035
1036
        $responseObject = json_decode($response->body());
1037
        if (!$response->successful())
1038
            throw new MonnifyFailedRequestException($responseObject->responseMessage ?? "Path '{$responseObject->path}' {$responseObject->error}", $responseObject->responseCode ?? $responseObject->status);
1039
1040
        return $responseObject->responseBody;
1041
    }
1042
1043
1044
}
1045