Direct Carrier Billing (DCB)
Direct Carrier Billing allows charging the customer's mobile carrier account. The payment is added to the phone bill or deducted from the prepaid balance. This is a popular micropayment method, especially in the gaming and digital content industries.
How it works
Differences from the standard API
DCB uses a separate endpoint and a slightly different data format:
| Feature | Standard API | DCB |
|---|---|---|
| Endpoint | api-payments.dpay.pl | secure.dpay.pl/dcb |
| Service identifier | service (name) | GUID |
| Amount format | PLN with dot ("10.23") | Grosz/cents ("1023") |
Endpoint
POST https://secure.dpay.pl/dcb/register
Content-Type: application/json
Request parameters
| Field | Type | Required | Description |
|---|---|---|---|
guid | string | Yes | Payment Point GUID (from the panel) |
value | string | Yes | Amount in grosz (e.g. "1023" = 10.23 PLN) |
url_success | string | Yes | URL after successful payment |
url_fail | string | Yes | URL after failed payment |
url_ipn | string | Yes | URL for IPN notifications |
checksum | string | Yes | SHA-256 checksum |
custom | string | No | Custom data (e.g. order ID) |
In DCB, the amount is specified in grosz (cents), not in zloty. The value "1023" means 10.23 PLN, not 1023 PLN.
GUID vs Service
For DCB, instead of the service name (service), you use the GUID identifier. You can find it in the dpay.pl panel:
- Go to Payment Points > Your point.
- Navigate to the Technical Settings tab.
- Copy the GUID value.
Generating the checksum
The checksum for DCB is generated using GUID instead of service:
sha256({GUID}|{SecretHash}|{value}|{url_success}|{url_fail}|{url_ipn})
Remember that value in the checksum is the amount in grosz (e.g. "1023"), not in zloty.
PHP
$guid = getenv('DPAY_DCB_GUID');
$secretHash = getenv('DPAY_SECRET_HASH');
$value = '1023'; // 10.23 PLN in grosz
$urlSuccess = 'https://myshop.com/success';
$urlFail = 'https://myshop.com/error';
$urlIpn = 'https://myshop.com/api/ipn';
$checksum = hash('sha256',
$guid . '|' . $secretHash . '|' . $value . '|' .
$urlSuccess . '|' . $urlFail . '|' . $urlIpn
);
JavaScript (Node.js)
const crypto = require('crypto');
const guid = process.env.DPAY_DCB_GUID;
const secretHash = process.env.DPAY_SECRET_HASH;
const value = '1023'; // 10.23 PLN in grosz
const urlSuccess = 'https://myshop.com/success';
const urlFail = 'https://myshop.com/error';
const urlIpn = 'https://myshop.com/api/ipn';
const checksum = crypto
.createHash('sha256')
.update(`${guid}|${secretHash}|${value}|${urlSuccess}|${urlFail}|${urlIpn}`)
.digest('hex');
Python
import hashlib
guid = os.environ['DPAY_DCB_GUID']
secret_hash = os.environ['DPAY_SECRET_HASH']
value = '1023' # 10.23 PLN in grosz
url_success = 'https://myshop.com/success'
url_fail = 'https://myshop.com/error'
url_ipn = 'https://myshop.com/api/ipn'
data = f'{guid}|{secret_hash}|{value}|{url_success}|{url_fail}|{url_ipn}'
checksum = hashlib.sha256(data.encode('utf-8')).hexdigest()
Request example
cURL
curl -X POST https://secure.dpay.pl/dcb/register \
-H "Content-Type: application/json" \
-d '{
"guid": "550e8400-e29b-41d4-a716-446655440000",
"value": "1023",
"url_success": "https://myshop.com/success",
"url_fail": "https://myshop.com/error",
"url_ipn": "https://myshop.com/api/ipn",
"checksum": "e3b0c44298fc1c149afb...",
"custom": "order-789"
}'
PHP - full example
<?php
$guid = getenv('DPAY_DCB_GUID');
$secretHash = getenv('DPAY_SECRET_HASH');
// Amount in grosz
$amountPLN = 10.23;
$value = (string)round($amountPLN * 100); // "1023"
$urlSuccess = 'https://myshop.com/success';
$urlFail = 'https://myshop.com/error';
$urlIpn = 'https://myshop.com/api/ipn';
$checksum = hash('sha256',
$guid . '|' . $secretHash . '|' . $value . '|' .
$urlSuccess . '|' . $urlFail . '|' . $urlIpn
);
$payload = json_encode([
'guid' => $guid,
'value' => $value,
'url_success' => $urlSuccess,
'url_fail' => $urlFail,
'url_ipn' => $urlIpn,
'checksum' => $checksum,
'custom' => 'order-789',
]);
$ch = curl_init('https://secure.dpay.pl/dcb/register');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if (!$result['error']) {
// Redirect the customer to the carrier page
header('Location: ' . $result['msg']);
exit;
}
API response
Success
{
"error": false,
"msg": "https://secure.dpay.pl/dcb/pay/abc-def-123-456",
"status": true,
"transactionId": "abc-def-123-456"
}
The customer will be redirected to a page where they confirm the payment using their phone number.
Error
{
"error": true,
"msg": "Invalid GUID",
"status": false
}
Amount conversion
Since DCB uses grosz, it's useful to have helper functions:
// PLN to grosz
function plnToGrosze(float $pln): string {
return (string)round($pln * 100);
}
// Grosz to PLN
function groszeToPln(string $grosze): float {
return intval($grosze) / 100;
}
// Example
$value = plnToGrosze(10.23); // "1023"
// PLN to grosz
function plnToGrosze(pln) {
return String(Math.round(pln * 100));
}
// Grosz to PLN
function groszeToPln(grosze) {
return parseInt(grosze, 10) / 100;
}
Amount limits
DCB is subject to limits imposed by mobile carriers:
| Carrier | Daily limit | Monthly limit |
|---|---|---|
| Varies depending on carrier and plan | Usually 50-200 PLN | Usually 200-500 PLN |
Exact limits depend on the carrier and the customer's account type (postpaid / prepaid).
Common errors
| Error | Cause | Solution |
|---|---|---|
Invalid GUID | Invalid identifier | Check the GUID in the panel |
Invalid value | Invalid amount | Provide the amount in grosz as a string |
DCB not available | Carrier does not support DCB | Suggest an alternative method |
Limit exceeded | Customer limit exceeded | Inform about the limit |
DCB works best for micropayments: mobile games, digital content subscriptions, one-time purchases up to several dozen zloty.