An Ukrposhta PHP SDK based on the official Ukrposhta API.
This library uses PHP 8.3+.
To use the Ukrposhta API, you need to have Bearer and Token for each API sub-portal (eCom, StatusTracking and AddressClassifier). After signing the contract, the bearer and token are issued by your manager. You can find more information here.
- Status Tracking - available.
- Address Classifier (counterparty) - available.
- Shipments - planned.
To get started, simply require the project using Composer.
composer require tibezh/ukrposhta-php-sdkThe SDK includes automatic retry logic for transient network errors (connection timeouts, DNS failures, etc.) with exponential backoff and jitter.
Default settings:
- Max retries: 3 attempts
- Base delay: 100ms (with exponential backoff: 100ms, 200ms, 400ms...)
You can customize retry behavior when creating a custom Request object:
use Ukrposhta\Request\Request;
use Ukrposhta\Tracking\Tracking;
// Create a custom request with retry settings.
$request = new Request(
logger: null, // Optional PSR-3 logger
maxRetries: 5, // Max retry attempts (default: 3)
retryDelayMs: 200 // Base delay in milliseconds (default: 100)
);
// Use the custom request with Tracking.
$tracking = new Tracking(
bearerStatusTracking: '[BEARER-TOKEN]',
request: $request
);To disable retries, set maxRetries to 0:
$request = new Request(logger: null, maxRetries: 0);The SDK supports PSR-3 logging. Pass any PSR-3 compatible logger to track API requests and responses:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Ukrposhta\Tracking\Tracking;
$logger = new Logger('ukrposhta');
$logger->pushHandler(new StreamHandler('path/to/ukrposhta.log', Logger::DEBUG));
$tracking = new Tracking(
bearerStatusTracking: '[BEARER-TOKEN]',
logger: $logger
);Request last status by barcode:
/** @var \Ukrposhta\Tracking\Entities\TrackingStatusInterface $barcodeLastStatus */
$barcodeLastStatus = (new \Ukrposhta\Tracking\Tracking())
->setAccessToken('[BEARER-STATUS-TRACKING-ACCESS-TOKEN]')
// To get results in English:
// ->setRequestLang('EN')
->requestBarcodeLastStatus('[BARCODE]');
// Prints event name value of the last status for the given barcode.
print $barcodeLastStatus->getEventName();Request all statuses by barcode:
/** @var \Ukrposhta\Tracking\Entities\TrackingStatusCollectionInterface $barcodeStatuses */
$barcodeStatuses = (new \Ukrposhta\Tracking\Tracking())
->setAccessToken('[BEARER-STATUS-TRACKING-ACCESS-TOKEN]')
// To get results in English:
// ->setRequestLang('EN')
->requestBarcodeStatuses('[BARCODE]');
// Prints "[date]: [eventName]" of each status for the given barcode.
foreach ($barcodeStatuses as $status) {
print $status->getDate()->format('c') . ': ' . $status->getEventName();
print '<br>';
}Request route by barcode:
/** @var \Ukrposhta\Tracking\Entities\TrackingRouteInterface $barcodeRoute */
$barcodeRoute = (new \Ukrposhta\Tracking\Tracking())
->setAccessToken('[BEARER-STATUS-TRACKING-ACCESS-TOKEN]')
// To get results in English:
// ->setRequestLang('EN')
->requestBarcodeRoute('[BARCODE]');
// Prints "[from] -> [to]" information for the given barcode.
print $barcodeRoute->getFrom() . ' -> ' . $barcodeRoute->getTo();The Address Classifier API allows you to search regions, districts, cities, streets, post offices and more.
Request regions:
use Ukrposhta\AddressClassifier\AddressClassifier;
use Ukrposhta\Utilities\Languages\LanguagesEnum;
$classifier = new AddressClassifier(
bearerCounterparty: '[BEARER-COUNTERPARTY-ACCESS-TOKEN]'
);
/** @var \Ukrposhta\AddressClassifier\Entities\Region\RegionCollectionInterface $regions */
$regions = $classifier->requestRegions('Київ');
foreach ($regions->all() as $region) {
print $region->getId() . ': ' . $region->getName();
print '<br>';
}Request districts by region ID:
/** @var \Ukrposhta\AddressClassifier\Entities\District\DistrictCollectionInterface $districts */
$districts = $classifier->requestDistrictsByRegionId(regionId: 1);
foreach ($districts->all() as $district) {
print $district->getId() . ': ' . $district->getName();
print '<br>';
}Request cities by region ID and district ID:
/** @var \Ukrposhta\AddressClassifier\Entities\City\CityCollectionInterface $cities */
$cities = $classifier->requestCityByRegionIdAndDistrictId(
regionId: 1,
districtId: 5,
nameUa: 'Бориспіль'
);
foreach ($cities->all() as $city) {
print $city->getId() . ': ' . $city->getName()->getByLanguage(LanguagesEnum::UA);
print '<br>';
}Request streets by city ID:
/** @var \Ukrposhta\AddressClassifier\Entities\Street\StreetCollectionInterface $streets */
$streets = $classifier->requestStreetByRegionIdAndDistrictIdAndCityId(
regionId: 1,
districtId: 5,
cityId: 100,
nameUa: 'Головна'
);
foreach ($streets->all() as $street) {
print $street->getId() . ': ' . $street->getName()->getByLanguage(LanguagesEnum::UA);
print '<br>';
}Request post offices by city ID:
/** @var \Ukrposhta\AddressClassifier\Entities\PostOffice\PostOfficeCollectionInterface $postOffices */
$postOffices = $classifier->requestPostOfficeByCityId(cityId: 100);
foreach ($postOffices->all() as $postOffice) {
print $postOffice->getPostIndex() . ': ' . $postOffice->getName()->getByLanguage(LanguagesEnum::UA);
print '<br>';
}Request nearest post offices by geolocation:
/** @var \Ukrposhta\AddressClassifier\Entities\NearestPostOffice\NearestPostOfficeCollectionInterface $nearestPostOffices */
$nearestPostOffices = $classifier->requestNearestPostOffices(
latitude: 50.4501,
longitude: 30.5234,
maxDistance: 1000 // meters
);
foreach ($nearestPostOffices->all() as $postOffice) {
print $postOffice->getFilialName() . ' - ' . $postOffice->getDistance() . ' m';
print '<br>';
}Fuzzy search for cities:
/** @var \Ukrposhta\AddressClassifier\Entities\CitySearchItem\CitySearchItemCollectionInterface $cities */
$cities = $classifier->requestSearchCity(
regionId: 1,
districtId: 5,
cityName: 'Борис', // partial name
language: LanguagesEnum::UA,
fuzzy: true
);
foreach ($cities->all() as $city) {
print $city->getName() . ' (' . $city->getTypeName() . ')';
print '<br>';
}All collection classes implement Countable and IteratorAggregate/Iterator interfaces, allowing you to:
// Get count of items.
$count = count($regions);
// Or use the count() method.
$count = $regions->count();
// Check if collection is empty.
if ($regions->isEmpty()) {
echo 'No regions found';
}
// Iterate directly with foreach.
foreach ($regions as $region) {
echo $region->getName();
}
// Get all items as array.
$allRegions = $regions->all();