Configuration
Each gateway has a config class (KbzPayConfig, WaveMoneyConfig, AyaPayConfig, YomaMmqrConfig, CyberSourceConfig) that takes named arguments. Gateways take the config object or an array of its snake_case keys. Every setting is required except the URL overrides and Yoma's webhook secret: there are no defaults, and a missing or blank setting throws a ConfigurationException naming it:
use Laranex\PhpMyanmarPayments\Exceptions\ConfigurationException;
use Laranex\PhpMyanmarPayments\KbzPay\KbzPay;
use Laranex\PhpMyanmarPayments\KbzPay\KbzPayConfig;
try {
$config = new KbzPayConfig(
appId: '...',
appKey: '',
merchantCode: '...',
timeoutSeconds: 30,
);
} catch (ConfigurationException $e) {
// e.g. kbz_pay "app_key"
error_log("missing {$e->gateway} setting \"{$e->key}\"");
throw $e;
}
$kbz = new KbzPay($config);$e->getMessage() reads The kbz_pay configuration is missing [app_key].
The time settings (timeoutSeconds, and Wave Money's timeToLiveSeconds) must be whole numbers greater than 0. Any other value throws the same exception with the message The kbz_pay configuration [timeout_in_seconds] must be a whole number greater than 0.
Endpoints
Every gateway uses its production endpoints. There is no switch between test and production: to test against a gateway's UAT environment, or to go through a proxy, set the URL overrides (see Testing Against UAT). A blank override means unset. Each config object exposes the URL actually used as a read-only property ($config->apiUrl, $config->baseUrl, …).
Config Options
KbzPayConfig
| Parameter | Type | Required | Description |
|---|---|---|---|
appId | string | Yes | appid issued by KBZ |
appKey | string | Yes | Secret key used to sign requests |
merchantCode | string | Yes | merch_code issued by KBZ |
timeoutSeconds | int | Yes | Seconds before the default HTTP client gives up. A missing one is reported as timeout_in_seconds |
apiUrl | ?string | No | Override the API base URL |
pwaUrl | ?string | No | Override the PWA checkout URL. Normalized to end with /, e.g. …/pwa/#/ |
WaveMoneyConfig
| Parameter | Type | Required | Description |
|---|---|---|---|
merchantId | string | Yes | Merchant ID issued by Wave |
secretKey | string | Yes | Hash secret key issued by Wave |
merchantName | string | Yes | Shown on Wave's payment page |
timeToLiveSeconds | int | Yes | Seconds the customer has to pay. A missing one is reported as time_to_live_in_seconds |
timeoutSeconds | int | Yes | Seconds before the default HTTP client gives up. A missing one is reported as timeout_in_seconds |
baseUrl | ?string | No | Override the API base URL |
authenticateUrl | ?string | No | Override the host the customer is redirected to |
AyaPayConfig
| Parameter | Type | Required | Description |
|---|---|---|---|
appKey | string | Yes | Public application key |
appSecret | string | Yes | Secret used for checksums |
timeoutSeconds | int | Yes | Seconds before the default HTTP client gives up. A missing one is reported as timeout_in_seconds |
baseUrl | ?string | No | Override the gateway base URL |
YomaMmqrConfig
| Parameter | Type | Required | Description |
|---|---|---|---|
merchantId | string | Yes | Merchant ID issued by Yoma |
clientId | string | Yes | OAuth client ID |
clientSecret | string | Yes | OAuth client secret |
webhookHashKey | string | Yes | Hash key issued by Yoma for verifying callbacks. A missing one is reported as webhook_hashkey |
apiVersion | string | Yes | The {version} segment of Yoma's API paths, e.g. v1rc |
timeoutSeconds | int | Yes | Seconds before the default HTTP client gives up. A missing one is reported as timeout_in_seconds |
webhookSecret | ?string | No | When set, callbacks must carry it in X-Webhook-Secret |
baseUrl | ?string | No | Override the API base URL |
CyberSourceConfig
| Parameter | Type | Required | Description |
|---|---|---|---|
profileId | string | Yes | Secure Acceptance profile ID |
accessKey | string | Yes | Profile access key |
secretKey | string | Yes | Profile secret key used to sign fields |
baseUrl | ?string | No | Override the Secure Acceptance base URL |
Production Endpoints
| Gateway | URL |
|---|---|
| KBZ Pay API | https://api.kbzpay.com/payment/gateway |
| KBZ Pay PWA | https://wap.kbzpay.com/pgw/pwa/#/ |
| Wave Money API | https://payments.wavemoney.io |
| Wave Money authenticate redirect | https://payments.wavemoney.io |
| AYA Payment Gateway | https://pgw.ayainnovation.com |
| Yoma MMQR | https://paymenthubapi.yomabank.com |
| CyberSource | https://secureacceptance.cybersource.com |
The URLs are class constants on the config classes: KbzPayConfig::PRODUCTION_API_URL, KbzPayConfig::PRODUCTION_PWA_URL, WaveMoneyConfig::PRODUCTION_URL, WaveMoneyConfig::PRODUCTION_AUTHENTICATE_URL, and PRODUCTION_URL on AyaPayConfig, YomaMmqrConfig and CyberSourceConfig.
Testing Against UAT
Each gateway issues separate UAT credentials. To use them, set the URL overrides to the gateway's UAT endpoints together with the UAT credentials:
| Gateway | Variable | Config argument | UAT value |
|---|---|---|---|
| KBZ Pay | KBZ_PAY_BASE_URL | apiUrl | http://api-uat.kbzpay.com/payment/gateway/uat |
| KBZ Pay | KBZ_PAY_PWA_BASE_REDIRECT_URL | pwaUrl | https://static.kbzpay.com/pgw/uat/pwa/#/ |
| Wave Money | WAVE_MONEY_BASE_URL | baseUrl | https://preprodpayments.wavemoney.io:8107 |
| Wave Money | WAVE_MONEY_AUTHENTICATE_URL | authenticateUrl | https://preprodpayments.wavemoney.io |
| AYA Payment Gateway | AYA_PAY_BASE_URL | baseUrl | https://uat-pgw.ayainnovation.com |
| Yoma MMQR | YOMA_MMQR_BASE_URL | baseUrl | https://devapi.yomabank.net |
| CyberSource | CYBER_SOURCE_BASE_URL | baseUrl | https://testsecureacceptance.cybersource.com |
Wave serves its API on port 8107 and the page the customer is redirected to on the same host without the port. Remove the overrides, and switch to the production credentials, when you go live.
From Environment Variables
Every config class and gateway has fromEnv($env = null), which reads getenv() merged with $_ENV by default and takes any array instead, such as one in tests. The variable names match the Laravel package, so one .env file works for both.
use Laranex\PhpMyanmarPayments\KbzPay\KbzPay;
use Laranex\PhpMyanmarPayments\KbzPay\KbzPayConfig;
$kbz = KbzPay::fromEnv();
// or
$config = KbzPayConfig::fromEnv();
$kbz = new KbzPay($config);Every variable is required unless it is marked optional. The values after = are examples:
# Every gateway that calls an API
MYANMAR_PAYMENTS_HTTP_TIMEOUT=30
# KBZ Pay
KBZ_PAY_APP_ID=
KBZ_PAY_APP_KEY=
KBZ_PAY_MERCHANT_CODE=
KBZ_PAY_BASE_URL= # optional override
KBZ_PAY_PWA_BASE_REDIRECT_URL= # optional override
# Wave Money
WAVE_MONEY_MERCHANT_ID=
WAVE_MONEY_SECRET_KEY=
WAVE_MONEY_MERCHANT_NAME=
WAVE_MONEY_TIME_TO_LIVE_IN_SECONDS=300
WAVE_MONEY_BASE_URL= # optional override
WAVE_MONEY_AUTHENTICATE_URL= # optional override
# AYA Payment Gateway (AYA_PGW_* names are read too)
AYA_PAY_APP_KEY=
AYA_PAY_APP_SECRET=
AYA_PAY_BASE_URL= # optional override
# Yoma MMQR
YOMA_MMQR_MERCHANT_ID=
YOMA_MMQR_CLIENT_ID=
YOMA_MMQR_CLIENT_SECRET=
YOMA_MMQR_WEBHOOK_HASHKEY=
YOMA_MMQR_API_VERSION=v1rc
YOMA_MMQR_WEBHOOK_SECRET= # optional
YOMA_MMQR_BASE_URL= # optional override
# CyberSource
CYBER_SOURCE_PROFILE_ID=
CYBER_SOURCE_ACCESS_KEY=
CYBER_SOURCE_SECRET_KEY=
CYBER_SOURCE_BASE_URL= # optional overrideMYANMAR_PAYMENTS_HTTP_TIMEOUT sets timeout_in_seconds for KBZ Pay, Wave Money, AYA and Yoma MMQR. The package never reads files itself: load the .env file with your framework or with vlucas/phpdotenv before calling fromEnv().
Credentials from a config file go through fromArray(), which reads the same settings as snake_case keys:
| Config class | Keys |
|---|---|
KbzPayConfig | app_id, app_key, merchant_code, timeout_in_seconds, api_url, pwa_url |
WaveMoneyConfig | merchant_id, secret_key, merchant_name, time_to_live_in_seconds, timeout_in_seconds, base_url, authenticate_url |
AyaPayConfig | app_key, app_secret, timeout_in_seconds, base_url |
YomaMmqrConfig | merchant_id, client_id, client_secret, webhook_hashkey, api_version, timeout_in_seconds, webhook_secret, base_url |
CyberSourceConfig | profile_id, access_key, secret_key, base_url |
time_to_live_in_seconds and timeout_in_seconds take an int or integer text such as '30'.
One Object for Every Gateway
MyanmarPayments builds each gateway from its config, on first use, and reuses it. Only the gateways you call need to be configured:
use Laranex\PhpMyanmarPayments\KbzPay\KbzPayConfig;
use Laranex\PhpMyanmarPayments\MyanmarPayments;
$payments = new MyanmarPayments([
'kbz_pay' => new KbzPayConfig(
appId: '...',
appKey: '...',
merchantCode: '...',
timeoutSeconds: 30,
),
'yoma_mmqr' => [
'merchant_id' => '...',
'client_id' => '...',
'client_secret' => '...',
'webhook_hashkey' => '...',
'api_version' => 'v1rc',
'timeout_in_seconds' => 30,
],
]);
$payments->kbzPay(); // KbzPay, the same instance on every call
// throws ConfigurationException:
// The wave_money configuration is missing [merchant_id].
$payments->waveMoney();
// reads each gateway's variables on first use
$fromEnv = MyanmarPayments::fromEnv();The keys kbz_pay, wave_money, aya_pay, yoma_mmqr and cyber_source take a config object or the array fromArray() reads, and the facade also takes the httpClient and cache arguments below, shared by every gateway it builds. $payments->cyberSource() returns the one CyberSource class.
HTTP Client
Gateways that call an API take any PSR-18 client as their second argument:
| Argument | Type | Description |
|---|---|---|
httpClient | ?Psr\Http\Client\ClientInterface | Sends every request. Use it for proxies, tracing, retries or test doubles. Without one, the gateway uses Guzzle with the config's timeoutSeconds when Guzzle is installed, and otherwise discovers an installed PSR-18 client |
use GuzzleHttp\Client;
use Laranex\PhpMyanmarPayments\KbzPay\KbzPay;
use Laranex\PhpMyanmarPayments\KbzPay\KbzPayConfig;
$client = new Client([
'timeout' => 10,
'proxy' => 'http://proxy.internal:3128',
]);
$kbz = new KbzPay(KbzPayConfig::fromEnv(), $client);fromEnv() takes the same client: KbzPay::fromEnv(null, $client).
A client you pass keeps its own timeout; timeoutSeconds is still required. A discovered client keeps its own timeout too. Request and stream objects are created with discovered PSR-17 factories, so a PSR-7 implementation such as guzzlehttp/psr7 or nyholm/psr7 must be installed. Guzzle ships one.
A failed request (connection error, timeout) throws an ApiException whose getPrevious() is the client's original exception.
CyberSource takes only its config: it only signs fields and makes no HTTP calls.
Token Cache
Yoma MMQR authenticates with an OAuth access token that lasts hours. YomaMmqr keeps it in a PSR-16 cache, its third argument:
use Laranex\PhpMyanmarPayments\YomaMmqr\YomaMmqr;
use Laranex\PhpMyanmarPayments\YomaMmqr\YomaMmqrConfig;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\Psr16Cache;
$cache = new Psr16Cache(new RedisAdapter(
RedisAdapter::createConnection('redis://localhost'),
));
$yoma = new YomaMmqr(YomaMmqrConfig::fromEnv(), null, $cache);The default is an in-memory ArrayCache that only lives for the current PHP process, so with PHP-FPM every request fetches a new token. Pass a shared cache (Redis, APCu, filesystem) in production. Pass cache to MyanmarPayments to share one cache with the Yoma gateway it builds. The token is stored under myanmar-payments.yoma-mmqr.token.<sha256(baseUrl|clientId)>, the same key in every Laranex SDK, so services in different languages can share one cache. $yoma->forgetToken() drops a cached token, e.g. after rotating the client secret.