very-code-com / suus-php
PHP client for the SUUS Logistics SOAP API (addOrder, getEvents, getDocument, getColliNo). First open-source PHP library for SUUS / Rohlig Logistics integration.
Requires
- php: ^8.2
- ext-curl: *
- ext-dom: *
- psr/log: ^2.0|^3.0
Requires (Dev)
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^10.5|^11.0
This package is auto-updated.
Last update: 2026-06-03 10:40:01 UTC
README
PHP client library for the SUUS Logistics (Rohlig Logistics) SOAP API.
The first open-source PHP package for SUUS/Rohlig freight integration - create shipments, track statuses, download documents, and handle multi-country business-day scheduling.
Requirements
- PHP 8.2+
ext-curlext-dom
Installation
composer require very-code-com/suus-php
Quick Start
use VeryCodeCom\Suus\SuusClient; use VeryCodeCom\Suus\Dto\{Address, Package, ShipmentOrder}; use VeryCodeCom\Suus\Enum\{Incoterm, PackageSymbol}; $client = SuusClient::sandbox('ws_yourlogin', 'your_password'); $result = $client->createShipment(new ShipmentOrder( reference: 'ORDER-2025-001', sender: new Address('Sender GmbH', 'Musterstr.', '1', '10115', 'Berlin', 'DE', phone: '+4930123'), receiver: new Address('Odbiorca Sp. z o.o.', 'Marszałkowska', '100', '00-026', 'Warszawa', 'PL', phone: '+48600000'), packages: [new Package(PackageSymbol::EUR, weightKg: 120.0)], incoterms: Incoterm::DAP, )); echo $result->shipmentNo; // e.g. OPLKRI2600895 echo $result->trackingUrl; // https://portal.suus.com/order-details/OPLKRI2600895
See examples/ for complete, runnable scripts.
Configuration
// Named constructors $client = SuusClient::sandbox('ws_login', 'secret'); $client = SuusClient::production('ws_login', 'secret'); // From environment variables (recommended) $config = SuusConfig::fromEnv(); // From array (framework config) $config = SuusConfig::fromArray(['login' => '…', 'password' => '…', 'env' => 'production']);
| Env variable | Required | Default | Description |
|---|---|---|---|
SUUS_LOGIN |
yes | - | API login (e.g. ws_yourlogin) |
SUUS_PASSWORD |
yes | - | API password |
SUUS_ENV |
no | production |
sandbox or production |
SUUS_TIMEOUT |
no | 30 |
Request timeout (seconds) |
SUUS_CONNECT_TIMEOUT |
no | 10 |
Connection timeout (seconds) |
API Reference
createShipment(ShipmentOrder $order): ShipmentResult
Creates a shipment via SUUS addOrder. Validates locally first.
Returns ShipmentResult with shipmentNo, reference, trackingUrl.
→ full example · international routes · additional services
fetchStatus(string $shipmentNo): StatusResult
Polls events via SUUS getEvents.
Returns StatusResult with status (ShipmentStatus enum), rawLatestCode, events[].
Note:
getEventsalways returnsPRJ000001in sandbox mode.
Status mapping:
| SUUS native codes | Normalized ShipmentStatus |
|---|---|
J_CR, KOL, M_KOL |
Created |
LOAD, ZALF, ZAL, M_DYS, WTRF |
InTransit |
ROZF, UNDI, UNLO |
Delivered |
ANUL |
Cancelled |
ZWRON, ZTF |
Failed |
fetchDocument(string $shipmentNo, DocumentType $type): string
Downloads a document as raw PDF bytes via SUUS getDocument.
DocumentType |
Description |
|---|---|
Label |
Standard A4 shipping label |
LabelA6 |
Thermal printer label (A6) |
ShippingOrder |
Shipping order document |
LoadingList |
Loading list |
fetchLabel(string $shipmentNo): string
Convenience shortcut for fetchDocument(…, DocumentType::Label).
getColliNumbers(string $shipmentNo): array
Returns per-package (colli) tracking numbers for multi-package shipments.
Package Types
PackageSymbol |
Description |
|---|---|
KAR |
Cardboard box |
EUR |
EUR pallet |
JED |
Disposable pallet |
PLT |
Standard pallet |
SKR |
Crate / chest |
ROL |
Roll |
DPL |
Double pallet |
DHP |
Large heavy package |
CHP |
Heavy package |
AGD |
Appliance |
INN |
Other |
WIA |
Bucket |
HB |
Half-block |
International Routes & Incoterms
incoterms is required whenever sender or receiver is not in Poland.
| Route | Incoterms required | Notes |
|---|---|---|
PL→PL |
No | Domestic, no restrictions |
PL→DE |
Yes | |
PL→AT |
Yes | |
PL→CH |
Yes | Swiss customs docs required |
DE→DE |
No | |
DE→AT |
Yes | |
DE→CH |
Yes | Swiss customs docs required |
Supported incoterms: EXW, FCA, FAS, FOB, CFR, CIF, CPT, CIP, DAP, DDP.
Business-Day Calendars
The library ships calendars for all countries where SUUS operates.
SuusClient defaults to PolishCalendar (required +2 PL business days advance notice).
Auto-detection: SuusClient automatically picks the right calendar based on the sender's country code - no manual configuration needed for standard routes.
| Class | Country | Holidays included |
|---|---|---|
PolishCalendar |
PL - Poland | 9 fixed + 4 Easter-based (Western) |
GermanCalendar |
DE - Germany | 5 federal fixed + 4 Easter-based (federal only, no Bundesland) |
AustriaCalendar |
AT - Austria | 9 fixed + 4 Easter-based (Western) |
SwitzerlandCalendar |
CH - Switzerland | 4 widely-observed fixed + 4 Easter-based (22/26 cantons) |
CzechCalendar |
CZ - Czech Rep. | 11 fixed + Good Friday + Easter Monday (Western) |
SlovakCalendar |
SK - Slovakia | 13 fixed + Good Friday + Easter Monday (Western) |
HungarianCalendar |
HU - Hungary | 8 fixed + 4 Easter-based (Western) |
RomanianCalendar |
RO - Romania | 10 fixed + 5 Easter-based (Orthodox Easter - differs from Western by up to 5 weeks) |
SlovenianCalendar |
SI - Slovenia | 12 fixed + Easter Sun/Mon + Whit Sunday (Western) |
To override (e.g. force a specific calendar regardless of sender country):
use VeryCodeCom\Suus\Calendar\GermanCalendar; $client = new SuusClient($config, calendar: new GermanCalendar());
All calendars implement BusinessCalendarInterface and work standalone:
$cal = new RomanianCalendar(); $cal->isBusinessDay(new DateTimeImmutable('2024-05-06')); // false - Orthodox Easter Monday $cal->isBusinessDay(new DateTimeImmutable('2024-04-01')); // true - Western Easter Mon (not RO holiday)
CalendarFactory::forCountry(string $cc) returns the right instance for any supported country code; unknown codes fall back to PolishCalendar.
Exceptions
All exceptions extend VeryCodeCom\Suus\Exception\SuusException.
| Exception | Trigger |
|---|---|
SuusValidationException |
Local validation failed (date, incoterms, package limits) |
SuusAuthException |
SUUS rejects credentials (DRG00001) |
SuusDuplicateReferenceException |
Reference already exists (PRJ00310) |
SuusApiException |
Other SUUS API errors - contains returnCode, errorCodes |
SuusTransportException |
Network error or non-200 HTTP response |
SuusResponseParseException |
SUUS returned unparseable XML |
Dependency Injection & Testing
The client accepts a custom TransportInterface, PSR-3 logger, and calendar override:
new SuusClient( config: SuusConfig, transport: TransportInterface = new CurlTransport(), logger: ?Psr\Log\LoggerInterface = null, calendar: ?BusinessCalendarInterface = null, // null = auto-detect from sender country )
Known SUUS API Quirks
lenghtCmtypo - SUUS uses<lenghtCm>(missing onet). Preserved intentionally.- PHP's
SoapClientis incompatible - SUUS uses RPC/encoded SOAP 1.1. This library uses raw cURL with manually constructed XML. - Response namespace quirk - SUUS SOAP responses swap
xmlns:cwandxmlns:ns1. Child elements carry no namespace prefix. getEvents/getDocumentalways fail in sandbox - OnlyaddOrderreturns real data in the test environment.- Loading date minimum - SUUS requires +2 Polish business days advance notice.
<auth>in every body - Unlike most SOAP services, SUUS embeds the auth block inside every operation's body, not in the SOAP header.
Running Tests
composer install # Unit tests (no network required) vendor/bin/phpunit --testsuite unit # Integration tests against the real SUUS sandbox SUUS_LOGIN=ws_xxx SUUS_PASSWORD=xxx SUUS_ENV=sandbox \ vendor/bin/phpunit --testsuite integration
License
Apache License 2.0 - see NOTICE for attribution requirements.
You may use, distribute, and modify this library freely. You must retain the NOTICE file and copyright notices in any redistribution or derivative work.
Built by Very Code. Contributions welcome - open an issue or PR.