Skip to main content

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:

FeatureStandard APIDCB
Endpointapi-payments.dpay.plsecure.dpay.pl/dcb
Service identifierservice (name)GUID
Amount formatPLN with dot ("10.23")Grosz/cents ("1023")

Endpoint

POST https://secure.dpay.pl/dcb/register
Content-Type: application/json

Request parameters

FieldTypeRequiredDescription
guidstringYesPayment Point GUID (from the panel)
valuestringYesAmount in grosz (e.g. "1023" = 10.23 PLN)
url_successstringYesURL after successful payment
url_failstringYesURL after failed payment
url_ipnstringYesURL for IPN notifications
checksumstringYesSHA-256 checksum
customstringNoCustom data (e.g. order ID)
Amount in grosz

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:

  1. Go to Payment Points > Your point.
  2. Navigate to the Technical Settings tab.
  3. 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})
caution

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:

CarrierDaily limitMonthly limit
Varies depending on carrier and planUsually 50-200 PLNUsually 200-500 PLN

Exact limits depend on the carrier and the customer's account type (postpaid / prepaid).

Common errors

ErrorCauseSolution
Invalid GUIDInvalid identifierCheck the GUID in the panel
Invalid valueInvalid amountProvide the amount in grosz as a string
DCB not availableCarrier does not support DCBSuggest an alternative method
Limit exceededCustomer limit exceededInform about the limit
DCB use cases

DCB works best for micropayments: mobile games, digital content subscriptions, one-time purchases up to several dozen zloty.