Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Post Nord Php Sdk Laravel Package

setono/post-nord-php-sdk

A PHP SDK for integrating PostNord shipping services into your application. Provides convenient access to PostNord APIs for creating shipments, generating labels, and tracking parcels, with a clean, framework-friendly interface for Laravel and other PHP projects.

View on GitHub
Deep Wiki
Context7

Getting Started

The Setono PostNord PHP SDK wraps PostNord's shipping and logistics APIs (shipment booking, label generation, tracking, and returns) in a typed PHP client. It is not a Laravel-first package — there is no service provider or facade — so you wire it up yourself inside config/services.php and a small binding in a service provider.

Minimal setup:

  1. composer require setono/post-nord-php-sdk:2.0.0-alpha.3 — pin the exact alpha. Alphas in a 2.0.0 line are pre-stable, and between alpha tags the public API can shift without a deprecation path.
  2. Add credentials to config/services.php:
    'postnord' => [
        'api_key'        => env('POSTNORD_API_KEY'),
        'customer_number'=> env('POSTNORD_CUSTOMER_NUMBER'),
        'base_uri'       => env('POSTNORD_BASE_URI', 'https://atapi2.postnord.com/rest'),
    ],
    
  3. Bind the SDK client as a singleton in AppServiceProvider::register() so you reuse the HTTP client and don't rebuild it per request.
  4. Look first at the SDK's Client / ClientFactory and the Model (DTO) directory. The DTOs are the real API surface — they tell you required vs. optional fields faster than the docs do.
  5. First use case: book a single shipment and fetch its label as a PDF. That exercise touches auth, DTO construction, error handling, and binary response handling all at once, which is where most integration time is spent.

Implementation Patterns

Wrap, don't sprinkle. Keep the SDK out of controllers and jobs. Create an App\Shipping\PostNord\PostNordGateway class that accepts your DTOs, maps them to SDK models, and returns your own result objects. When the SDK breaks (and in alpha it will), you change one class.

Bind via factory, not direct instantiation. Register a singleton client in a dedicated provider:

$this->app->singleton(PostNord::class, fn ($app) => new PostNord(
    apiKey: config('services.postnord.api_key'),
    customerNumber: config('services.postnord.customer_number'),
    baseUri: config('services.postnord.base_uri'),
));

Queue label generation. Booking + PDF retrieval are two HTTP round-trips with a binary payload. Run them in a queued job (ShouldQueue), store the resulting PDF on a disk (Storage::disk('s3')->put(...)), and persist only the path plus the shipment ID. Never hold a PDF blob in a job payload or a DB column.

Persist the external identity immediately. Store PostNord's shipment/parcel ID as soon as the booking response returns, before attempting label retrieval. If label generation fails you can retry the label without double-booking a shipment.

Treat tracking as pull-primary, push-optional. The SDK exposes tracking lookups; PostNord also supports push notifications. Pull on a schedule (every 15–30 min for active shipments) as the reliable path, and layer webhook handling on top as an accelerator. Webhooks arrive out of order, so always reconcile against the pull API rather than trusting payload state.

Idempotency. PostNord's booking endpoints are not universally idempotent. Generate your own idempotency key (order ID + attempt) and persist it so a retried job doesn't create duplicate shipments — check "do I already have a shipment ID for this order?" before calling.

Testing. The SDK is HTTP-client based, so swap in a PSR-18 mock or a fake HTTP client and return recorded fixtures. Commit fixtures for at least: successful booking, validation error, auth failure, and label-ready. This is the only way to have fast tests without sandbox credentials.

Gotchas and Tips

  • Alpha churn is the headline risk. No prior assessment exists and the release notes here are a bare changelog link, so there's no reliable signal of what changed between alpha tags. Pin with "2.0.0-alpha.3" (exact) and read the diff on GitHub before bumping. Do not use ^2.0@dev.
  • Customer number ≠ API key. A 401/403 usually means credentials; a 400 about unknown customer means your customer_number doesn't match the key's account, or you're pointing the same key at sandbox and production base URIs. Keep them paired in config per environment.
  • Base URI is environment-specific. Sandbox and production are different hosts, not just different keys. A hardcoded base_uri silently sends sandbox traffic to production or vice versa.
  • Unit and date conventions bite. Weights are typically grams in the API while your shipping domain likely uses kilograms; dates are ISO strings with timezone semantics that affect cutoff/booking dates. Centralise conversions in your gateway — never in the controller.
  • Cross-border needs customs data. Shipments crossing Nordic borders require HS codes, item values, and currency. This is the most common reason a booking fails in the wild. Treat customs fields as a first-class part of your shipment DTO, not an afterthought.
  • PDF labels are binary, not JSON. Ensure your HTTP layer doesn't try to JSON-decode the label response. A "JSON decode error" on a 200 usually means you parsed a PDF response as JSON.
  • Extension points. The SDK's HTTP client is typically injectable — use that for logging, retry middleware, and a X-Request-Id on every call. That request ID is what PostNord support will ask for when you file a ticket.
  • No Laravel eventing out of the box. Emit your own events (ShipmentBooked, LabelReady, TrackingUpdated) from the gateway so the rest of the app stays decoupled from the SDK, and so you can swap carriers later without touching listeners.
  • Rate limits and retries. Retry only on connection errors and 5xx/429, with backoff; never blindly retry booking on timeout — the shipment may have been created. Mark the job failed and reconcile by order ID first.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager