monapay / php-sdk
SDK PHP zero-dependency cho MONA Pay
Requires
- php: >=7.4
- ext-curl: *
- ext-json: *
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
PHP SDK for the MONA Pay API: create checkout links and VietQR codes, manage virtual accounts, webhooks and email notifications, and verify signed webhooks.
Requires PHP 7.4+ with the curl and json extensions. PSR-4 autoloaded under MonaPay\, no third-party packages.
Install
composer require monapay/php-sdk
Quick start
export MONAPAY_CLIENT_ID="client-id" export MONAPAY_CLIENT_SECRET="client-secret"
<?php use MonaPay\Client; $mona = Client::fromEnv(); $checkout = $mona->checkouts->create([ 'amount' => 250000, 'order_code' => 'DH10234', 'return_url' => 'https://shop.example/payment/return', ]); header('Location: ' . $checkout['checkout_url']);
Usage
Client
use MonaPay\Client; // From environment variables (see Configuration) $mona = Client::fromEnv(); // Or explicitly. Constructor arguments: // ($username, $password, $clientSecret = null, $baseUrl = 'https://api.monapay.vn', // $transport = null, $timeout = 30, $clientId = null) $client = new Client('', '', getenv('MONAPAY_CLIENT_SECRET'), 'https://api.monapay.vn', null, 30, getenv('MONAPAY_CLIENT_ID')); var_dump($mona->me());
- Client credentials (
clientId+clientSecret) are the recommended login. Username/password is a legacy fallback and does not work for accounts with 2FA enabled. - The token is cached until 60 seconds before
expires_in. A request that fails with HTTP 401 triggers a new login and is retried once. - Methods return the
datafield of the API response. Errors are thrown asMonaPay\ApiExceptionwithstatusandbody.
Resources
| Property | Methods |
|---|---|
$keys |
generate, list, destroy, reveal, rotate |
$bankAccounts |
list |
$va |
register, verify, registerNotification, verifyNotification, list |
$paymentProfile |
get, set, rotateReturnSecret, revealReturnSecret |
$checkouts |
create, get, list, cancel |
$qr |
generate, cancel |
$transactions |
list, iterate, retry |
$sandbox |
createTransaction |
$webhooks |
list, create, update, remove, test |
$webhookLogs |
list, stats |
$emailConfigs |
list, get, create, update, remove, verify, resendVerification, test |
$emailLogs |
list, stats |
$emailSuppressions |
list, remove |
$keys->generate() returns the client_secret only once, so store it right away. The client also picks it up for subsequent requests.
Hosted checkout
$checkout = $mona->checkouts->create([ 'amount' => 250000, 'order_code' => 'DH10234', 'return_url' => 'https://shop.example/payment/return', ]); header('Location: ' . $checkout['checkout_url']);
create and cancel send an Idempotency-Key header generated by the SDK; pass a second argument to use your own key. Fulfil orders from the CHECKOUT_PAID webhook or from $mona->checkouts->get($id), not from the browser redirect.
Sandbox
$tx = $mona->sandbox->createTransaction([ 'virtual_account_number' => 'MONA123', 'amount' => 10000, 'description' => 'Sandbox test', ]);
Dynamic VietQR
$qr = $mona->qr->generate([ 'ownerNumber' => '123456789', 'ownerType' => 'ORG', 'merchantId' => 'MC00012345', 'terminalId' => 'TM0001', 'orderId' => 'DH10234', 'virtualAccountPrefix' => 'MONA', 'beneficiaryName' => 'CONG TY ABC', 'amount' => 2500000, 'description' => 'Thanh toan DH10234', ]); echo $qr['qr_data_url'];
Transactions
foreach ($mona->iterTransactions('MONA0000010234', 1, 100) as $tx) { echo $tx['transaction_code'] . ': ' . $tx['amount']; } $mona->transactions->retry($transactionId, 'WEBHOOK', $webhookConfigId);
Webhooks
Register an HMAC webhook:
$mona->webhooks->create([ 'name' => 'Web ban hang', 'webhook_url' => 'https://shop.example/webhooks/monapay', 'auth_type' => 'HMAC_SHA256', 'secret_key' => getenv('MONA_WEBHOOK_SECRET'), 'payload_format' => 'application/json', ]);
Verify incoming requests against the raw body. Webhook::verify reads the X-Mona-Timestamp and X-Mona-Signature headers and rejects timestamps older than $tolerance seconds (default 300).
use MonaPay\Webhook; $rawBody = file_get_contents('php://input'); $result = Webhook::verify($rawBody, getallheaders(), getenv('MONA_WEBHOOK_SECRET')); if (!$result['ok']) { http_response_code(401); exit($result['reason']); } saveOnce($result['payload']['transaction_code'], $result['payload']); http_response_code(200);
Store transaction_code under a unique constraint so redelivered webhooks are not processed twice. WordPress REST and Laravel handlers are in examples/.
Configuration
Client::fromEnv() reads:
| Variable | Purpose |
|---|---|
MONAPAY_CLIENT_ID, MONAPAY_CLIENT_SECRET |
API key credentials (recommended) |
MONAPAY_USERNAME, MONAPAY_PASSWORD |
Legacy password login; does not work for accounts with 2FA enabled |
MONAPAY_BASE_URL |
API base URL, defaults to https://api.monapay.vn |
The examples above also use MONA_WEBHOOK_SECRET for the webhook signing secret.
Documentation: https://monapay.vn/docs
Development
php tests/run.php
License
MIT
MONA Pay is part of MONA Cloud by The MONA Group.