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 hashwaveMoney()->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 proofwaveMoney()->handleCallback($request)
Wave Money: payment request, authenticate, result

Initiating a Payment ​

php
use Laranex\LaravelMyanmarPayments\Facades\MyanmarPayments;
use Laranex\PhpMyanmarPayments\WaveMoney\WaveMoneyItem;
use Laranex\PhpMyanmarPayments\WaveMoney\WaveMoneyPaymentData;

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

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

$order->update(['wave_reference' => $data->merchantReferenceId]);

return redirect()->away($payment->url);

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 takes a name and an amount (Amount|int) in whole kyat, greater than 0. The items are summed with exact integer arithmetic, never floats.

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. Read it from $data->merchantReferenceId.

Handling Callbacks ​

php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Laranex\LaravelMyanmarPayments\Facades\MyanmarPayments;
use Laranex\PhpMyanmarPayments\Exceptions\SignatureVerificationException;

Route::post('/payments/wave/callback', function (Request $request) {
    try {
        $callback = MyanmarPayments::waveMoney()->handleCallback($request);
    } catch (SignatureVerificationException) {
        abort(400);
    }

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

    return MyanmarPayments::acknowledge($callback);
})->name('payments.wave.callback');

$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. 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 ​

PropertyWave Money value
orderIdYour orderId
url{authenticate_url}/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

MyanmarPayments::acknowledge($callback) turns acknowledgement into a CallbackResponse (Responsable). handleCallback() accepts an Illuminate\Http\Request or a CallbackRequest.

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 WaveMoneyPaymentData(...)InvalidPaymentDataExceptionA value breaks the rules above. Nothing is sent
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.

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