Skip to content

Wave Money ​

Wave Money's payment gateway sends the customer to a Wave payment page to pay with their WavePay wallet.

CallWhat it doesReturns
$waveMoney->initiate($data)Redirect to Wave's payment pageRedirectPayment
$waveMoney->handleCallback($request)Verify the callbackPaymentCallback

Wave Money has no status API in this package: the callback is the only payment result.

Responses shows what Wave Money puts in each result.

How it works ​

Wave sends the customer back to your return URL and posts the result to your callback URL separately.

Wave Money: payment request, authenticate, resultCustomerYour appWave MoneyCheck outPayment request with hash$waveMoney->initiate($data)transaction_idRedirect to authenticate/authenticate?transaction_id=…Pay with WavePayBack to the frontend URLreturnUrl: not proof of paymentBackend result URL callbackPOST to callbackUrl, hashValueVerified callback is proof$waveMoney->handleCallback($request)
Wave Money: payment request, authenticate, result

Initiating a Payment ​

php
use Laranex\PhpMyanmarPayments\WaveMoney\WaveMoney;
use Laranex\PhpMyanmarPayments\WaveMoney\WaveMoneyConfig;
use Laranex\PhpMyanmarPayments\WaveMoney\WaveMoneyItem;
use Laranex\PhpMyanmarPayments\WaveMoney\WaveMoneyPaymentData;

$waveMoney = new WaveMoney(new WaveMoneyConfig(
    merchantId: '...',
    secretKey: '...',
    merchantName: 'My Shop',
    timeToLiveSeconds: 300,
    timeoutSeconds: 30,
));

$data = new WaveMoneyPaymentData(
    orderId: 'ORDER_'.$order->id,
    callbackUrl: 'https://shop.test/payments/wave/callback',
    returnUrl: 'https://shop.test/orders/'.$order->id,
    description: 'Order #'.$order->id,
    items: [
        new WaveMoneyItem('Product A', 6000),
        new WaveMoneyItem('Product B', 4000),
    ],
);

$payment = $waveMoney->initiate($data);

// Store $data->merchantReferenceId with the order.

header('Location: '.$payment->url);
exit;

WaveMoneyPaymentData ​

ParameterTypeRequiredRules
orderIdstringYesYour order ID. One order can have several payment attempts
callbackUrlstringYesAbsolute http or https URL that Wave posts the result to. Wave may require HTTPS with a CA-issued certificate in production
returnUrlstringYesAbsolute http or https URL Wave sends the customer back to. Not proof of payment
descriptionstringYesShown to the customer
itemslist<WaveMoneyItem>YesAt least one item
amountAmount|int|nullNoWhole kyat, greater than 0 (Wave doesn't accept decimals). null charges the sum of the items. Wave only accepts MMK
merchantReferenceId?stringNoUnique ID of this attempt. null or empty means a random ID

WaveMoneyItem has a name and an amount (Amount|int) in whole kyat, greater than 0. The items are summed with exact integer arithmetic, never floats; $data->amount holds the total that will be charged.

Merchant Reference ID ​

Wave rejects a reused merchant_reference_id (409 Record already exists), so every attempt, including a retry of the same order, needs a new one. Leave it empty to get a fresh random ID, and store it: Wave marks orderId as optional in callbacks, while merchantReferenceId is always present. new WaveMoneyPaymentData() writes the generated ID to $data->merchantReferenceId once the data passes validation.

Handling Callbacks ​

php
// POST /payments/wave/callback
use Laranex\PhpMyanmarPayments\Exceptions\SignatureVerificationException;
use Laranex\PhpMyanmarPayments\Http\CallbackRequest;

try {
    $callback = $waveMoney->handleCallback(CallbackRequest::fromGlobals());
} catch (SignatureVerificationException) {
    http_response_code(400);
    echo 'invalid callback';
    exit;
}

if ($callback->isSuccessful()) {
    // $callback->orderId is your orderId
    // $callback->raw['merchantReferenceId'] is the attempt's reference
    // $callback->gatewayReference is Wave's transactionId
}

$callback->acknowledgement->send();

$callback->orderId falls back to merchantReferenceId when Wave's orderId is missing, null or empty.

Responses ​

What Wave Money puts in each property. See Results and PaymentCallback & Status for the full classes. A property the gateway didn't send is null. raw holds plain PHP values (JSON numbers stay strings with their exact text), while the typed properties such as amount keep the exact text Wave sent.

initiate() → RedirectPayment ​

Property / MethodWave Money value
flow()PaymentFlow::Redirect
orderIdYour $data->orderId
url{authenticateUrl}/authenticate?transaction_id=… (URL-encoded), e.g. https://payments.wavemoney.io/authenticate?transaction_id=…
gatewayReferenceWave transaction_id. Always set
rawWave's /payment response: message (success), transaction_id

The attempt's merchantReferenceId is not on the result: read it from $data->merchantReferenceId.

handleCallback() → PaymentCallback ​

Property / MethodWave Money value
orderIdWave orderId, falling back to merchantReferenceId when it is missing, null or empty
statusstatus mapped, see Statuses
gatewayStatusWave status, trimmed, e.g. PAYMENT_CONFIRMED
gatewayReferenceWave transactionId
amountWave amount, e.g. 10000
rawThe verified body: status, merchantId, orderId, merchantReferenceId, frontendResultUrl, backendResultUrl, initiatorMsisdn, amount, timeToLiveSeconds, paymentDescription, currency, additionalField1–5, transactionId, paymentRequestId, requestTime, hashValue
acknowledgementHTTP 200, empty body, Content-Type: text/plain

Statuses ​

Only PAYMENT_CONFIRMED means the customer paid.

Wave statusPaymentStatus
PAYMENT_CONFIRMEDSuccessful
INSUFFICIENT_BALANCEPending
ACCOUNT_LOCKED, BILL_COLLECTION_FAILEDFailed
PAYMENT_REQUEST_CANCELLEDCanceled
TRANSACTION_TIMED_OUT, SCHEDULER_TRANSACTION_TIMED_OUTExpired
anything elseUnknown

SCHEDULER_TRANSACTION_TIMED_OUT arrives up to 15 minutes after the time-to-live ends.

Errors ​

CallThrowsWhen
new WaveMoneyItem(...)InvalidPaymentDataExceptionIts amount is a negative int
new WaveMoneyPaymentData(...)InvalidPaymentDataExceptionA value breaks the rules above. Nothing is sent. Item errors use items.0.name and items.0.amount keys
initiate()ApiExceptionWave answers with an HTTP error, a message other than success, or no transaction_id
handleCallback()SignatureVerificationExceptionhashValue doesn't match, or a hashed field holds an object or array

httpStatus tells Wave's rejections apart: 400 invalid hash, 404 unknown merchant, 409 reused reference, 422 validation (gatewayCode is VALIDATION_ERROR). When Wave can't be reached, initiate() throws ApiException with httpStatus 0 and the original error as getPrevious().

Released under the MIT License, except where a package says otherwise.