MB WAY (Portugal)
Accepting this payment channel requires an additional agreement with the acquiring agent designated by dpay.pl.
MB WAY is a popular mobile payment method in Portugal. The customer authorizes the payment directly in the MB WAY app on their phone by providing only their phone number.
How it works
/api/v1_0/payments/registerComplete payment registration contract: parameters, checksum, and error codes.Full contract in the API Reference
Endpoint
POST https://api-payments.dpay.pl/api/v1_0/payments/register
Content-Type: application/json
The payment registration endpoint supports up to 120 requests per minute.
Request parameters
| Field | Type | Required | Description |
|---|---|---|---|
transactionType | string | Yes | "mb_way_direct" |
service | string | Yes | Service name from the dashboard |
value | string | Yes | Amount in EUR |
currency_code | string | Yes | "EUR" |
channel | string | Yes | "373" - the MB WAY channel |
email | string | Yes (with channel) | Customer's email address |
client_name | string | Yes (with channel) | Customer's first name |
client_surname | string | Yes (with channel) | Customer's last name |
accept_tos | boolean | Yes (with channel) | Confirmation that the customer accepts the terms and conditions |
phone_number | string | Yes | Phone number in +351XXXXXXXXX format |
url_success | string | Yes | URL after a successful payment |
url_fail | string | Yes | URL after a failed payment |
url_ipn | string | Yes | URL for IPN notifications |
checksum | string | Yes | SHA-256 checksum |
device_info | object | Yes | Customer device information (all fields listed below) |
The channel field with the value "373" is required for transactionType: "mb_way_direct". Always send it, in test mode too - the simulator does not check it, but on a production service registration without channel fails. Providing the channel field also requires email, client_name, client_surname, and accept_tos. If any of them is missing, the request fails validation (HTTP 422).
MB WAY accepts EUR only. The service must have EUR enabled - if it does not, registration fails with Currency code "EUR" does not match the service currency code "PLN". In that case, contact your dpay.pl account manager.
Phone number format
Use the standard international phone number format:
+351XXXXXXXXX
Where:
+351- Portugal's country codeXXXXXXXXX- 9-digit phone number
Example: +351912345678
device_info object
For mb_way_direct transactions, all fields below are required:
{
"browserAcceptHeader": "text/html,application/xhtml+xml",
"browserJavaEnabled": "false",
"browserLanguage": "pt-PT",
"browserColorDepth": 24,
"browserScreenHeight": 1080,
"browserScreenWidth": 1920,
"browserTZ": 0,
"browserUserAgent": "Mozilla/5.0 ...",
"systemFamily": "Windows",
"deviceID": "device-uuid-1234",
"applicationName": "Chrome",
"geoLocalization": "38.7223,-9.1393"
}
The browserJavaEnabled field is required and must be the string "true" or "false" (not a boolean). The browserColorDepth, browserScreenHeight, browserScreenWidth, and browserTZ fields are integers. If any field in the device_info object is missing, the request fails validation (HTTP 422).
In the dpay SDKs, browserJavaEnabled is optional - if you do not set it, the SDK does not send it, and MB WAY registration fails validation (HTTP 422). Set it explicitly, for example withBrowserJavaEnabled(false) in PHP and Java, with_browser_java_enabled(False) in Python, with_browser_java_enabled(false) in Ruby, browserJavaEnabled: false in Node.js or BrowserJavaEnabled: dpay.Bool(false) in Go. The SDK converts the boolean into the required string.
Request example
cURL
curl -X POST https://api-payments.dpay.pl/api/v1_0/payments/register \
-H "Content-Type: application/json" \
-d '{
"transactionType": "mb_way_direct",
"service": "abc123",
"value": "14.99",
"currency_code": "EUR",
"channel": "373",
"email": "customer@example.com",
"client_name": "Joao",
"client_surname": "Silva",
"accept_tos": true,
"phone_number": "+351912345678",
"url_success": "https://myshop.example/success",
"url_fail": "https://myshop.example/failure",
"url_ipn": "https://myshop.example/api/ipn",
"checksum": "e3b0c44298fc1c149afb...",
"device_info": {
"browserAcceptHeader": "text/html,application/xhtml+xml",
"browserJavaEnabled": "false",
"browserLanguage": "pt-PT",
"browserColorDepth": 24,
"browserScreenHeight": 1080,
"browserScreenWidth": 1920,
"browserTZ": 0,
"browserUserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"systemFamily": "Windows",
"deviceID": "device-uuid-1234",
"applicationName": "Chrome",
"geoLocalization": "38.7223,-9.1393"
}
}'
PHP
<?php
$service = getenv('DPAY_SERVICE');
$secretHash = getenv('DPAY_SECRET_HASH');
$value = '14.99';
$urlSuccess = 'https://myshop.example/success';
$urlFail = 'https://myshop.example/failure';
$urlIpn = 'https://myshop.example/api/ipn';
$checksum = hash('sha256',
$service . '|' . $secretHash . '|' . $value . '|' .
$urlSuccess . '|' . $urlFail . '|' . $urlIpn
);
$payload = json_encode([
'transactionType' => 'mb_way_direct',
'service' => $service,
'value' => $value,
'currency_code' => 'EUR',
'channel' => '373',
'email' => $_POST['email'],
'client_name' => $_POST['client_name'],
'client_surname' => $_POST['client_surname'],
'accept_tos' => true,
'phone_number' => '+351' . $_POST['phone_number'],
'url_success' => $urlSuccess,
'url_fail' => $urlFail,
'url_ipn' => $urlIpn,
'checksum' => $checksum,
'device_info' => [
'browserAcceptHeader' => 'text/html,application/xhtml+xml',
'browserJavaEnabled' => 'false',
'browserLanguage' => 'pt-PT',
'browserColorDepth' => 24,
'browserScreenHeight' => 1080,
'browserScreenWidth' => 1920,
'browserTZ' => 0,
'browserUserAgent' => $_SERVER['HTTP_USER_AGENT'],
'systemFamily' => 'Windows',
'deviceID' => $_POST['device_id'],
'applicationName' => 'Chrome',
'geoLocalization' => $_POST['geo'],
],
]);
$ch = curl_init('https://api-payments.dpay.pl/api/v1_0/payments/register');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
API response
Success - awaiting confirmation
{
"error": false,
"msg": "Internal processing",
"status": true,
"transactionId": "abc-def-123-456"
}
The status field is a boolean (true/false). The Internal processing response means the transaction has been accepted and the customer must now confirm the payment in the MB WAY app. The result arrives asynchronously (see Payment result).
Registration error (HTTP 400)
Errors detected during registration, such as a missing phone number, use the following response format:
{
"status": "failed",
"message": "Phone number is required for MB Way Direct transactions.",
"errors": []
}
Payment rejection in the registration response
When the payment is rejected already at registration, the transaction is cancelled and the error code and description are returned in additionalInfo:
{
"error": true,
"msg": "Transaction canceled",
"status": false,
"transactionId": "abc-def-123-456",
"additionalInfo": {
"error": "E0506",
"error_description": "Alias does not exist"
}
}
In production, this is how errors detected before the notification is sent to the MB WAY app are returned, for example a phone number not registered with MB WAY (E0506) or invalid request data (E0103). In test mode, all failure scenarios are returned in this format, with simulator codes (see Testing in test mode).
Payment result
| Situation | In production | In test mode |
|---|---|---|
| The customer confirmed the payment | IPN and the payment.succeeded webhook after confirmation in the app | IPN and the payment.succeeded webhook a few seconds after registration |
| The customer declined the payment in the app or did not confirm it | Usually asynchronously, after the customer's decision or when the confirmation time runs out: the payment.failed webhook; occasionally immediately in the registration response (E0399) | Immediately in the registration response (USER_DECLINED, TIMEOUT) and the payment.failed webhook |
| Number not registered, invalid data | Immediately in the registration response (for example E0506, E0103) and the payment.failed webhook | Immediately in the registration response (ALIAS_NOT_FOUND, SYSTEM_ERROR) and the payment.failed webhook |
The IPN carries no status and is sent only after a successful payment. A decline or a missing confirmation is reported only by the payment.failed webhook - if you rely on IPN alone, you learn about a failed payment by querying the transaction status. For a decline returned in the registration response, the event has generic_decline in failure.code and the decline code (for example USER_DECLINED) in failure.provider_code (see Decline codes).
Form example
<form id="mbway-form">
<label for="phone">Phone number (Portugal)</label>
<div style="display: flex; align-items: center;">
<span>+351</span>
<input
type="tel"
id="phone"
name="phone_number"
maxlength="9"
pattern="[0-9]{9}"
placeholder="912345678"
required
/>
</div>
<button type="submit">Pay with MB WAY</button>
</form>
<script>
document.getElementById('mbway-form').addEventListener('submit', async (e) => {
e.preventDefault();
const phone = document.getElementById('phone').value;
const response = await fetch('/api/pay/mb-way', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone_number: phone }),
});
const result = await response.json();
if (!result.error) {
// Show a message while waiting for confirmation
alert('Confirm the payment in the MB WAY app');
}
});
</script>
Testing in test mode
In test mode, you can use special phone numbers to simulate different scenarios without having the MB WAY app:
| Phone number | Scenario | Registration response | Code in additionalInfo.error |
|---|---|---|---|
+351900000001 | Payment completed successfully | Internal processing, then IPN and payment.succeeded after a few seconds | - |
+351900000002 | Success after a longer wait | Internal processing, IPN and payment.succeeded after a longer while | - |
+351900000400 | User rejected the payment in the app | Transaction canceled | USER_DECLINED |
+351900000401 | Timeout - no confirmation | Transaction canceled | TIMEOUT |
+351900000402 | Phone number not registered with MB WAY | Transaction canceled | ALIAS_NOT_FOUND |
+351900000500 | System error | Transaction canceled | SYSTEM_ERROR |
In test mode, a decline and a timeout are returned immediately in the registration response - in production, the customer decides in the app, so the same result arrives asynchronously, with the payment.failed webhook (see Payment result). Example response for +351900000400:
{
"error": true,
"msg": "Transaction canceled",
"status": false,
"transactionId": "abc-def-123-456",
"additionalInfo": {
"error": "USER_DECLINED",
"error_description": "User declined the transaction"
}
}
Enter the test number exactly as shown in the table, with a leading + (spaces and hyphens are removed). A number without +, for example 351900000400, is rejected with Phone number is required for MB Way Direct transactions., and a valid number outside the table (for example +351912345678) is treated by the simulator as unknown and results in a simulated successful payment.
The full list of test numbers and details is available on the Test environment page.
Common errors
| Message / code | Where it appears | Cause | Solution |
|---|---|---|---|
Phone number is required for MB Way Direct transactions. | message (HTTP 400) | Missing phone number or a format that cannot be normalized (the number is rejected) | Use the +351XXXXXXXXX format |
Currency code "EUR" does not match the service currency code "PLN". | message (HTTP 400) | EUR is not enabled for the service | Ask your dpay.pl account manager to enable EUR for the service |
PLN currency code is not allowed for MB WAY DIRECT transactions. | message (HTTP 400) | PLN currency in an MB WAY request | Use currency_code: "EUR" |
device_info.browserJavaEnabled validation error | HTTP 422 | The field is missing or is a boolean instead of a string (common with SDKs when the field is not set explicitly) | Send "true" or "false" |
USER_DECLINED, TIMEOUT, ALIAS_NOT_FOUND, SYSTEM_ERROR | additionalInfo | Simulator scenarios in test mode | See Testing in test mode |
E0506 - Alias does not exist | additionalInfo | Phone number not registered with MB WAY | Suggest another payment method |
E0508 - Alias not available | additionalInfo | Alias temporarily unavailable | Ask the customer to try again |
E0399 - Transaction declined | additionalInfo | Payment rejected (for example, no confirmation or the customer declined it) | Ask the customer to try again |
E0309 - Transaction not found | additionalInfo | Transaction unknown to the provider | Register the payment again |
E0103 - Request validation failed | additionalInfo | Invalid request data | Check that all fields, including device_info, are present |
E0099 - Operation not allowed for this alias | additionalInfo | Operation not allowed for this phone number | Suggest another payment method |
MB WAY is available exclusively to customers with a Portuguese phone number and the MB WAY app installed.