PHPackages                             sashalenz/nova-poshta-api - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. sashalenz/nova-poshta-api

ActiveLibrary[API Development](/categories/api)

sashalenz/nova-poshta-api
=========================

Nova Poshta API SDK for Laravel

3.6.2(today)0664↑123.5%1MITPHPPHP ^8.2

Since Mar 14Pushed 5d ago1 watchersCompare

[ Source](https://github.com/sashalenz/nova-poshta-api)[ Packagist](https://packagist.org/packages/sashalenz/nova-poshta-api)[ Docs](https://github.com/sashalenz/nova-poshta-api)[ RSS](/packages/sashalenz-nova-poshta-api/feed)WikiDiscussions main Synced today

READMEChangelog (10)Dependencies (20)Versions (20)Used By (1)

Nova Poshta API SDK for Laravel
===============================

[](#nova-poshta-api-sdk-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/280de0a18503f8a7c0752e748573bc4800f98bf7cffe6351b361c47b7be19dd7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73617368616c656e7a2f6e6f76612d706f736874612d6170692e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/sashalenz/nova-poshta-api)[![Total Downloads](https://camo.githubusercontent.com/cd039ec0168ebf28306f8fb659affc3323692607c4ae44cce4092c4ca464e42a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73617368616c656e7a2f6e6f76612d706f736874612d6170692e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/sashalenz/nova-poshta-api)

A Laravel SDK for the [Nova Poshta](https://developers.novaposhta.ua/documentation) JSON API. Wraps every public NP method behind a fluent, fully-typed builder backed by [`spatie/laravel-data`](https://github.com/spatie/laravel-data) request and response objects, with built-in caching, retries and a typed exception hierarchy.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 10, 11, 12 or 13
- A registered NP business account with an API key ([cabinet → settings → API](https://my.novaposhta.ua/settings/index#apikeys))

Installation
------------

[](#installation)

```
composer require sashalenz/nova-poshta-api
```

The service provider registers itself via Laravel's package discovery — no manual wiring needed.

Publish the config file (optional, only needed if you want to override the API URL or pin a default API key in source):

```
php artisan vendor:publish --tag="nova-poshta-api-config"
```

Configuration
-------------

[](#configuration)

```
NOVA_POSHTA_API_KEY=your-default-api-key
NOVA_POSHTA_API_URL=https://api.novaposhta.ua/v2.0/json/   # optional, this is the default
```

The default API key is used whenever you call a model with `::make()` and no argument. Pass an explicit key (`::make($apiKey)`) when you need to talk to a specific counterparty's account — useful in multi-sender systems where every sender has their own NP cabinet.

```
use Sashalenz\NovaPoshtaApi\ApiModels\Address;

// Uses NOVA_POSHTA_API_KEY from env
$cities = Address::make()->getCities($request);

// Uses a different counterparty's key for this call only
$senderInvoices = InternetDocument::make($sender->np_api_key)->getDocumentList($request);
```

Quick start
-----------

[](#quick-start)

```
use Sashalenz\NovaPoshtaApi\ApiModels\Address;
use Sashalenz\NovaPoshtaApi\ApiModels\Address\RequestData\GetCitiesRequest;

$cities = Address::make()
    ->cache(60 * 60) // optional: cache the response for 1 hour
    ->getCities(GetCitiesRequest::from([
        'limit' => 20,
        'findByString' => 'Київ',
    ]));

foreach ($cities as $city) {
    echo "{$city->ref}  {$city->description}\n";
}
```

Every method returns either a single `Spatie\LaravelData\Data` object or a `Spatie\LaravelData\DataCollection` — see [`spatie/laravel-data`](https://github.com/spatie/laravel-data) for the available helpers (`->toArray()`, `->toCollection()`, iteration, etc.).

API Models
----------

[](#api-models)

The SDK is split into one class per NP API module. Each class is a fluent builder — call `::make($apiKey)` then the method you want; arguments are typed `*Request` data objects.

### `Address` — locations &amp; address book

[](#address--locations--address-book)

Lookup of cities, settlements, warehouses, streets, plus CRUD over an address book stored under your counterparty.

MethodReturnsPurpose`getCities(GetCitiesRequest)``DataCollection`City lookup by name or ref`getSettlements(GetSettlementsRequest)``DataCollection`Full settlement directory (cities + villages)`searchSettlements(SearchSettlementsRequest)``SearchSettlementData`Autocomplete-style settlement search`searchSettlementStreets(SearchSettlementStreetsRequest)``SettlementStreetData`Street search inside a settlement`getStreet(GetStreetRequest)``DataCollection`Street lookup`getAreas()``DataCollection`Oblast list`getWarehouses(GetWarehousesRequest)``DataCollection`NP branch list (with filters by city, type, etc.)`getWarehouseTypes()``DataCollection`Branch types directory`save(AddressRequest)``AddressData`Create an address book entry`update(AddressRequest)``AddressData`Update one`delete(RefRequest)``RefData`Delete one```
use Sashalenz\NovaPoshtaApi\ApiModels\Address;
use Sashalenz\NovaPoshtaApi\ApiModels\Address\RequestData\GetWarehousesRequest;

$warehouses = Address::make()
    ->cache(60 * 60 * 24)
    ->getWarehouses(GetWarehousesRequest::from([
        'cityRef' => $city->ref,
        'limit' => 500,
    ]));
```

### `Common` — reference dictionaries

[](#common--reference-dictionaries)

Read-only directories used when filling out shipment forms — cargo types, payer types, packaging, time intervals. Most are excellent candidates for long-lived caching since they barely change.

MethodPurpose`getCargoTypes()`Cargo type list (parcel, documents, cargo, pallets, tires)`getBackwardDeliveryCargoTypes()`Cargo types valid for return-delivery`getPayersForRedelivery` *(via `getTypesOfPayersForRedelivery()`)*Who pays the cash-on-delivery fee`getPalletsList()`Standard pallet sizes`getPackList(GetPackListRequest?)`Available packaging`getTiresWheelsList()`Tire/wheel reference list`getOwnershipFormsList()`Legal ownership forms (LLC, FOP…)`getCargoDescriptionList(GetCargoDescriptionListRequest?)`Allowed free-text cargo descriptions`getTimeIntervals(GetTimeIntervalsRequest)`Time slots for "Доставка у точно визначений час"`getMessageCodeText()`NP API message code dictionary### `Counterparty` — senders, recipients, third parties

[](#counterparty--senders-recipients-third-parties)

Manages counterparties (юр./фіз. особи) registered to your account — anyone you ship from or to.

MethodPurpose`getCounterparties(GetCounterpartiesRequest)`List your counterparties (Sender / Recipient / ThirdPerson)`getCatalogCounterparty(GetCatalogCounterpartyRequest)`Search the public NP catalog by EDRPOU/name`getCounterpartyOptions(RefRequest)`Allowed shipment options for a counterparty`getCounterpartyAddresses(GetCounterpartyAddressesRequest)`Addresses bound to a counterparty`getCounterpartyContactPersons(RefRequest)`Contact persons under a counterparty`save(SaveCounterpartyRequest)`Create a counterparty`update(UpdateCounterpartyRequest)`Update one`delete(RefRequest)`Delete one### `ContactPerson` — counterparty contacts

[](#contactperson--counterparty-contacts)

CRUD for contact persons under a counterparty (e.g. a department lead inside a Sender LLC).

MethodPurpose`save(SaveContactPersonRequest)`Create`update(UpdateContactPersonRequest)`Update`delete(RefRequest)`Delete### `InternetDocument` — express waybills (TTN)

[](#internetdocument--express-waybills-ttn)

The bread and butter — create and manage shipments.

MethodPurpose`getDocumentPrice(GetDocumentPriceRequest)`Price estimate before creating a TTN`getDocumentDeliveryDate(GetDocumentDeliveryDateRequest)`ETA estimate before creating a TTN`save(SaveInternetDocumentRequest)`Issue a new TTN`update(UpdateInternetDocumentRequest)`Update an existing TTN (only while it's not yet at NP's hands)`delete(DeleteInternetDocumentRequest)`Cancel a TTN`getDocument(RefRequest)`Fetch one document by ref`getDocumentList(GetDocumentListRequest)`List your documents (by date range, status, etc.)```
use Sashalenz\NovaPoshtaApi\ApiModels\InternetDocument;
use Sashalenz\NovaPoshtaApi\ApiModels\InternetDocument\RequestData\GetDocumentPriceRequest;
use Sashalenz\NovaPoshtaApi\Enums\CargoType;
use Sashalenz\NovaPoshtaApi\Enums\ServiceType;

$price = InternetDocument::make($sender->api_key)->getDocumentPrice(
    GetDocumentPriceRequest::from([
        'citySender' => $sender->city_ref,
        'cityRecipient' => $recipientCityRef,
        'weight' => 5.5,
        'serviceType' => ServiceType::WAREHOUSE_WAREHOUSE,
        'cargoType' => CargoType::CARGO,
        'cost' => 1000,
        'seatsAmount' => 1,
    ])
);

echo $price->cost; // UAH
```

### `ScanSheet` — registries

[](#scansheet--registries)

Bundles TTNs into a daily registry for the courier hand-off.

MethodPurpose`getScanSheetList()`List your registries`getScanSheet(GetScanSheetRequest)`Detail of a single registry`insertDocuments(InsertDocumentsRequest)`Add TTNs to a registry`removeDocuments(RemoveDocumentsRequest)`Remove TTNs from a registry`deleteScanSheet(DeleteScanSheetData)`Delete an empty registry### `TrackingDocument` — status polling

[](#trackingdocument--status-polling)

```
use Sashalenz\NovaPoshtaApi\ApiModels\TrackingDocument\TrackingDocument;
use Sashalenz\NovaPoshtaApi\ApiModels\TrackingDocument\RequestData\GetStatusDocumentsRequest;
use Sashalenz\NovaPoshtaApi\ApiModels\TrackingDocument\RequestData\DocumentData;

$statuses = TrackingDocument::make()->getStatusDocuments(
    GetStatusDocumentsRequest::from([
        'documents' => [
            DocumentData::from(['documentNumber' => '20400000000001', 'phone' => '380501234567']),
            DocumentData::from(['documentNumber' => '20400000000002', 'phone' => '380501234567']),
        ],
    ])
);

foreach ($statuses as $status) {
    echo "{$status->number}: {$status->status} (statusCode={$status->statusCode})\n";
}
```

`statusCode` follows NP's published numeric status table — see [NP docs](https://developers.novaposhta.ua/view/model/a99d2f28-7c30-11ec-8ced-005056b2dbe1/method/a9956c79-7c30-11ec-8ced-005056b2dbe1) for the full list.

### `AdditionalService` — returns, redirects, EW changes

[](#additionalservice--returns-redirects-ew-changes)

Operations on TTNs that already left your hands.

MethodPurpose`checkPossibilityCreateReturn(CheckPossibilityCreateReturnRequest)`Can this TTN be returned, and to where`checkPossibilityForRedirecting(...)`Can this TTN be redirected`checkPossibilityChangeEW(CheckPossibilityChangeEWRequest)`Can this TTN be edited`getReturnReasons()`Pickable return reasons`getReturnReasonsSubtypes(GetReturnReasonsSubtypesRequest)`Reason subtypes for a given reason`save(SaveAdditionalServiceRequest)`Create a return / redirect / EW-change order`delete(RefRequest)`Cancel one`getReturnOrdersList(GetOrdersListRequest?)`Your existing return orders`getRedirectionOrdersList(GetOrdersListRequest?)`Your existing redirect orders`getChangeEWOrdersList(GetOrdersListRequest?)`Your existing change-EW orders`save()` returns `AdditionalServiceSaveData{ number, ref }` — `number` is the new return / redirect TTN, persist it to track the chain.

Caching
-------

[](#caching)

Any model can cache its response by chaining `->cache($seconds)` before the method call. Use `-1` (the default when no argument is passed) to cache forever.

```
// Cache cities for 24h — the directory rarely changes
Address::make()->cache(60 * 60 * 24)->getCities($request);

// Cache forever (until you flush manually)
Common::make()->cache()->getCargoTypes();
```

The cache key is composed of the model name, the called method and a base64-serialized hash of the request payload, so different inputs to the same method get different cache slots.

Enums
-----

[](#enums)

EnumUse`CargoType`Cargo type for `InternetDocument::save` (`CARGO`, `DOCUMENTS`, `PARCEL`, `TIRES_WHEELS`, `PALLET`)`ServiceType`Pickup/delivery model (`WAREHOUSE_WAREHOUSE`, `WAREHOUSE_DOORS`, `DOORS_WAREHOUSE`, `DOORS_DOORS`)`PayerType`Who pays (`SENDER`, `RECIPIENT`, `THIRD_PERSON`)`PaymentMethod``CASH` or `NON_CASH``OrderType``AdditionalService` order type — `ORDER_CARGO_RETURN`, `ORDER_REDIRECTING`, `ORDER_CHANGE_EW``CounterpartyType``SENDER`, `RECIPIENT`, `THIRD_PERSON``CounterpartyProperty``PRIVATE_PERSON` or `ORGANIZATION`Marking — print URLs
--------------------

[](#marking--print-urls)

`Sashalenz\NovaPoshtaApi\Marking` builds public NP cabinet URLs for label / scan-sheet PDFs. They're plain `https://my.novaposhta.ua/...` links you can hand to the browser or pipe into a PDF printer — no JSON API call involved.

```
use Sashalenz\NovaPoshtaApi\Marking;

// 85x85 label, HTML or pdf8
$labelUrl = Marking::printMarking('pdf8', ['20400000000001'], $apiKey);

// 100x100 zebra-printer label
$zebraUrl = Marking::printZebraMarking('pdf', ['20400000000001'], $apiKey);

// Scan sheet (registry) PDF
$sheetUrl = Marking::printScanSheet($scanSheetRef, $apiKey);

// Combined documents print
$docsUrl = Marking::printDocument(['ref-1', 'ref-2'], 'pdf', $apiKey);
```

`printMarking()` and `printDocument()` return `null` if you pass an unsupported `$type` — only `'html'` and `'pdf'`/`'pdf8'` are accepted.

Error handling
--------------

[](#error-handling)

Every request goes through `Request::make()`, which raises one of two exception types — both extending `NovaPoshtaException`:

ExceptionWhenTypical use`NovaPoshtaApiUnavailableException`NP itself is unreachable: cURL connection reset, DNS failure, timeout, or any 5xx responseTreat as a transient infrastructure issue — retry later, render an empty/cached fallback, alert the on-call channel separately from code errors`NovaPoshtaException`NP returned an HTTP 4xx, or a 200 response whose body contained an `errors[]` array / `success: false`Application-level error — the request itself is the problem (bad TTN, missing API key, malformed payload). Surface to the user / log and move onExisting `catch (NovaPoshtaException)` sites pick up the unavailable subclass automatically, so legacy code keeps working. Catch the subclass first when you need to react differently to downtime:

```
use Sashalenz\NovaPoshtaApi\Exceptions\NovaPoshtaApiUnavailableException;
use Sashalenz\NovaPoshtaApi\Exceptions\NovaPoshtaException;

try {
    $cities = Address::make()->getCities($request);
} catch (NovaPoshtaApiUnavailableException $e) {
    // NP is down — fall back to cached results, suppress UI noise
    return $cachedCities;
} catch (NovaPoshtaException $e) {
    // Something is wrong with our request — log and surface to the user
    report($e);
    return collect();
}
```

For Bugsnag / Sentry, route `NovaPoshtaApiUnavailableException` to a lower severity (e.g. `warning`) so the dashboard isn't flooded during NP's evening flapping windows:

```
// bootstrap/app.php — Laravel 11+
->withExceptions(fn (Exceptions $exceptions) => $exceptions
    ->report(function (NovaPoshtaApiUnavailableException $e) {
        Bugsnag::notifyException($e, fn ($report) => $report->setSeverity('warning'));
        return false; // skip default reporting
    })
    ->dontReport([NovaPoshtaException::class])
)
```

The HTTP layer also auto-retries 3 times with a 100ms backoff and a 3s per-attempt timeout before giving up — so by the time an exception leaves the SDK, NP really wasn't reachable.

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Oleksandr Petrovskyi](https://github.com/sashalenz)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

51

—

FairBetter than 95% of packages

Maintenance99

Actively maintained with recent releases

Popularity18

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity66

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~67 days

Recently: every ~7 days

Total

19

Last Release

0d ago

Major Versions

2.1.1 → 3.0.02025-01-09

PHP version history (5 changes)2.0.0PHP ^8.1

2.1.0PHP ^8.2

3.0.0PHP ^8.4

3.0.1PHP ^8.2||^8.4

3.2.0PHP ^8.2|^8.4|^8.5

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/13202688?v=4)[Oleksandr Petrovskyi](/maintainers/sashalenz)[@sashalenz](https://github.com/sashalenz)

---

Top Contributors

[![sashalenz](https://avatars.githubusercontent.com/u/13202688?v=4)](https://github.com/sashalenz "sashalenz (23 commits)")

---

Tags

apilaravelnova poshtanovaposhta.ua

### Embed Badge

![Health badge](/badges/sashalenz-nova-poshta-api/health.svg)

```
[![Health](https://phpackages.com/badges/sashalenz-nova-poshta-api/health.svg)](https://phpackages.com/packages/sashalenz-nova-poshta-api)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M345](/packages/psalm-plugin-laravel)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

816333.6k3](/packages/defstudio-telegraph)[api-platform/laravel

API Platform support for Laravel

58171.4k14](/packages/api-platform-laravel)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5021.9k](/packages/simplestats-io-laravel-client)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
