A modern PHP library for interacting with the Ukrainian delivery service Nova Poshta via their API 2.0. This package provides a clean, type-safe interface for all Nova Poshta services including settlements, warehouses, counterparties, documents, and additional services.
- Full API 2.0 Coverage: Complete implementation of Nova Poshta API 2.0
- Type Safety: Built with PHP 8.3+ features including strict types and readonly classes
- Service-Oriented Architecture: Clean separation of concerns with dedicated service classes
- Exception Handling: Comprehensive error handling with specific exception types
- PSR-4 Compatible: Follows PSR-4 autoloading standards
- Logging Support: PSR-3 compatible logging interface
- Modern PHP: Leverages enums, readonly properties, and other modern PHP features
- PHP 8.3 or higher
- cURL extension
- JSON extension
Install via Composer:
composer require grisaia/nova-poshta
<?php
use Grisaia\NovaPoshta\NovaPoshtaAPI;
use Grisaia\NovaPoshta\Services\SettlementService;
// Initialize the API client with your API key
$api = new NovaPoshtaAPI('your-api-key-here');
// Optional: Set custom timeout (default is 4 seconds)
$api->setTimeoutInSeconds(10);
// Optional: Add PSR-3 compatible logger
$api->setLogger($yourLogger);
// Get a service instance
$settlementService = $api->getService(SettlementService::class);
use Grisaia\NovaPoshta\Services\SettlementService;
use Grisaia\NovaPoshta\MethodProperties\Address\SettlementSearchProperties;
$settlementService = $api->getService(SettlementService::class);
// Get settlements list with pagination
$settlements = $settlementService->getSettlementList(
page: 1,
limit: 20,
regionRef: 'some-region-ref', // optional
areaRef: 'some-area-ref', // optional
hasWarehouse: true // optional
);
// Search for settlements
$searchProps = new SettlementSearchProperties();
$searchProps->setCityName('Київ');
$searchProps->setLimit(10);
$searchResults = $settlementService->searchSettlements($searchProps);
// Search settlement streets
$streets = $settlementService->searchSettlementStreets(
streetName: 'Хрещатик',
settlementRef: 'settlement-ref',
limit: 10,
page: 1
);
use Grisaia\NovaPoshta\Services\WarehouseService;
use Grisaia\NovaPoshta\MethodProperties\Address\WarehouseListProperties;
$warehouseService = $api->getService(WarehouseService::class);
// Get warehouses with filters
$warehouseProps = new WarehouseListProperties();
$warehouseProps->setCityName('Київ');
$warehouseProps->setPage(1);
$warehouseProps->setLimit(50);
$warehouseProps->setHasPostFinance(true);
$warehouseProps->satHasBicycleParking(false);
$warehouses = $warehouseService->getWarehouseList($warehouseProps);
// Get warehouse types
$warehouseTypes = $warehouseService->getWarehouseTypeList();
use Grisaia\NovaPoshta\Services\CounterpartyService;
use Grisaia\NovaPoshta\MethodProperties\Counterparty\CounterpartySaveProperties;
use Grisaia\NovaPoshta\MethodProperties\Counterparty\CounterpartyListProperties;
use Grisaia\NovaPoshta\DataAdapters\Enums\CounterpartyPersonType;
use Grisaia\NovaPoshta\DataAdapters\Enums\CounterpartyType;
$counterpartyService = $api->getService(CounterpartyService::class);
// Create a new counterparty
$saveProps = new CounterpartySaveProperties();
$saveProps->setFirstName('Іван');
$saveProps->setLastName('Петренко');
$saveProps->setPhone('0501234567');
$saveProps->setCounterpartyType(CounterpartyType::PrivatePerson);
$result = $counterpartyService->saveCounterparty($saveProps);
// Get counterparties list
$listProps = new CounterpartyListProperties(CounterpartyPersonType::Sender);
$listProps->setPage(1);
$listProps->setLimit(20);
$listProps->findByString('Петренко');
$counterparties = $counterpartyService->getCounterpartyList($listProps);
// Get contact persons for a counterparty
$contacts = $counterpartyService->getCounterpartyContactPerson('counterparty-ref', 1);
use Grisaia\NovaPoshta\Services\DocumentService;
$documentService = $api->getService(DocumentService::class);
// Get document information
try {
$document = $documentService->getDocument('20450123456789');
echo "Document status: " . $document->getStateName();
} catch (DocumentNotFoundException $e) {
echo "Document not found";
}
// Track multiple documents
$trackingNumbers = ['20450123456789', '20450987654321'];
$trackingResults = $documentService->getDocumentTrackingStatus($trackingNumbers);
foreach ($trackingResults->getTrackingItems() as $tracking) {
echo "Number: " . $tracking->getNumber() . " - Status: " . $tracking->getStatus() . "\n";
}
use Grisaia\NovaPoshta\Services\DocumentFileService;
use Grisaia\NovaPoshta\DataAdapters\Enums\DocumentPrintType;
$fileService = $api->getService(DocumentFileService::class);
// Save document labels to file
try {
$fileService->saveDocumentsFile(
destination: '/path/to/labels.pdf',
documents: ['20450123456789', '20450987654321'],
type: DocumentPrintType::Sticker,
timeout: 10
);
echo "Labels saved successfully";
} catch (FileSaveException $e) {
echo "Failed to save file: " . $e->getMessage();
}
use Grisaia\NovaPoshta\Services\AdditionalService;
use Grisaia\NovaPoshta\MethodProperties\AdditionalService\Save\OrderRedirectingProperties;
$additionalService = $api->getService(AdditionalService::class);
// Request package redirection
$redirectProps = new OrderRedirectingProperties();
$redirectProps->setDocumentNumber('20450123456789');
$redirectProps->setRecipientPhone('0501234567');
$redirectProps->setRecipientContactName('Нове Ім\'я');
$redirectProps->setNoteAddressRecipient('Нова адреса');
$result = $additionalService->requestAdditionalService($redirectProps);
use Grisaia\NovaPoshta\Services\CityService;
use Grisaia\NovaPoshta\MethodProperties\Address\CityListProperties;
$cityService = $api->getService(CityService::class);
// Get cities list
$cityProps = new CityListProperties();
$cityProps->setPage(1);
$cityProps->setLimit(50);
$cityProps->findByString('Київ');
$cities = $cityService->getCityList($cityProps);
// Convert settlement to city (Nova Poshta specific requirement)
try {
$city = $cityService->getCityBySettlement('settlement-ref');
} catch (CityBySettlementException $e) {
echo "Settlement not found or cannot be converted to city";
}
Service | Description |
---|---|
SettlementService |
Manage settlements, areas, regions, and street search |
WarehouseService |
Handle warehouse listings and types |
CounterpartyService |
Manage counterparties and contact persons |
DocumentService |
Document operations and tracking |
DocumentFileService |
Generate and save document files (labels, invoices) |
CityService |
City management and settlement conversion |
AdditionalService |
Additional services (redirections, changes, returns) |
ScanSheetService |
Scan sheet operations |
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('nova-poshta');
$logger->pushHandler(new StreamHandler('path/to/logfile.log', Logger::INFO));
$api = new NovaPoshtaAPI('your-api-key');
$api->setLogger($logger);
The library provides specific exception types for different error scenarios:
use Grisaia\NovaPoshta\Exception\QueryFailed\QueryFailedException;
use Grisaia\NovaPoshta\Exception\QueryFailed\CurlException;
use Grisaia\NovaPoshta\Exception\DocumentNotFoundException;
use Grisaia\NovaPoshta\Exception\BadValueException;
try {
$result = $settlementService->getSettlementList(1, 10);
} catch (CurlException $e) {
// Handle network errors
echo "Network error: " . $e->getMessage();
} catch (QueryFailedException $e) {
// Handle API errors
echo "API error: " . $e->getMessage();
} catch (BadValueException $e) {
// Handle data validation errors
echo "Data error: " . $e->getMessage();
}
# Run all tests
composer test
# Run individual test suites
composer phpunit
composer phpstan
composer phpmd
# Fix code style
composer fix
This package uses several tools to maintain code quality:
- PHPStan: Static analysis (level max)
- PHPMD: Mess detection
- PHPUnit: Unit testing
The package follows a clean architecture pattern:
src/
├── NovaPoshtaAPI.php # Main entry point
├── Services/ # Service layer
├── DataAdapters/ # Data transformation layer
│ ├── Entities/ # Entity classes
│ ├── Enums/ # Enumeration classes
│ └── Result/ # Result wrapper classes
├── MethodProperties/ # Request parameter classes
├── Exception/ # Exception hierarchy
└── Normalizer/ # Data normalization utilities
Contributions are welcome! Please feel free to submit a Pull Request. Make sure to:
- Follow the existing code style
- Add tests for new functionality
- Update documentation as needed
- Run the test suite before submitting
This project is licensed under the MIT License - see the LICENSE file for details.
If you encounter any issues or have questions, please:
- Check the API documentation
- Review existing issues
- Create a new issue with detailed information