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

Econt Laravel Package

gdinko/econt

Laravel integration for Econt courier services, offering convenient API access for shipping labels, delivery pricing, tracking, offices, and order fulfillment. Simplifies connecting PHP and Laravel applications to Econt.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer and publish the config:

composer require gdinko/econt
php artisan vendor:publish --provider="Gdinko\Econt\EcontServiceProvider"

The config file (config/econt.php) holds your Econt API credentials, the environment/mode flag (demo vs. production), and the base URLs. Set these via .env — never inline them — before touching the API. Econt issues separate demo and production credentials, so keep one .env per environment and be explicit about which mode is active; a sandbox key against the live URL (or vice versa) produces confusing auth errors rather than a clean failure.

First use case: the read-only lookups. Start by fetching countries, cities, and offices, because almost every other call (pricing, labels, tracking) is fed by the IDs these return. A good smoke test is:

use Gdinko\Econt\Facades\Econt;

$countries = Econt::getCountries();
$cities    = Econt::getCities($countryId);
$offices   = Econt::getOffices($cityId);

The facade resolves the underlying client from the container, so you can also inject the class directly where you prefer constructor dependencies (the cleaner choice inside services and jobs). Use these calls to confirm credentials, connectivity, and the response shape before building anything that creates labels — label creation is the operation you can least afford to debug blind.

Look first at the package's method signatures (they map closely to Econt's own JSON API), then at the config. Between the two you can infer payload shapes without reading the source.

Implementation Patterns

Separate reads from writes. Cities, offices, streets, and countries change rarely; cache them (per country/city) with a TTL measured in days and refresh on a schedule. Price quotes and tracking are live and should never be cached. Labels and courier requests are write operations and must not be retried blindly.

Wrap write operations in queued jobs. Label creation, courier pickup requests, and label deletion are the calls that cost money and mutate state on Econt's side. Push them onto a queue with a small $tries count (1–2), and persist the returned label/parcel number in your own table before acknowledging the job. If the worker dies between Econt's response and your DB write, you have an orphaned parcel — reconcile by tracking status, not by resubmitting.

Model the shipment as a domain object. Do not scatter Econt payload arrays across controllers. Build one ShipmentData-style DTO or value object (sender, receiver, weight, declared value, packCount, shipmentType), then have a single ShipmentService translate it into the Econt payload. This keeps the inevitable API quirks in one place and makes it trivial to test your mapping without hitting the network.

class ShipmentService
{
    public function __construct(private Econt $econt) {}

    public function quote(ShipmentData $s): array
    {
        return $this->econt->getPrice($this->payloadFor($s));
    }

    public function create(ShipmentData $s): array
    {
        return $this->econt->createLabel($this->payloadFor($s));
    }
}

Pricing before ordering. In checkout flows, call getPrice at cart/checkout time and store the quoted amount alongside the order. Econt's live pricing can drift with weight, destination, and deliveryMode, so never recompute the customer-facing shipping charge after the fact — capture it, and treat a later mismatch as an internal cost, not a chargeback to the customer.

Tracking as a polling loop. There is no meaningful long-lived subscription here; run a scheduled command that pulls track for parcels in "in transit" states, writes each status transition as an event row, and stops polling once delivered or returned. Idempotency matters — key on the parcel number plus status code so you don't emit duplicate notifications.

Webhook/route glue. For the customer-facing side, expose a small controller that serves cached office lists (by city) to your frontend office-picker, and an internal endpoint for the tracking timeline. Neither should proxy Econt live on every request.

Gotchas and Tips

Demo vs. production is a footgun. The mode flag is easy to leave on demo in staging and then assume it's the bug when labels don't appear in production. Log the resolved base URL and mode at boot in non-production, and add an assertion that production environments never run with demo credentials.

Response shapes are nested and inconsistent. Econt responses often wrap results in outer keys and mix label/parcel objects. Dump the raw array once per endpoint into a fixture and code against that fixture — do not hand-type DTOs from the docs. Keep the raw response stored alongside your processed record; when Econt adds a field or changes a status string, the raw copy is what saves you.

Weight and dimensions are in Econt's units, not yours. Declared value, weight (kg), and volume are easy to get wrong by a factor, and wrong weight silently changes your price and can invalidate a label. Centralize unit conversion in the DTO and test it explicitly.

Network failures need distinguishing. A timeout is not the same as a rejection. Timeouts on label creation leave you genuinely uncertain whether a parcel exists — resolve with a tracking/lookup call before retrying, never with a blind resubmit. Set a modest HTTP timeout in the config and handle connection exceptions distinctly from API error responses.

Error payloads aren't exceptions. Most wrappers return the decoded error body rather than throwing. Guard every write with a shape check on the response (isset($res['label']), presence of an error key) and throw your own typed exception so failures surface in logs and Sentry instead of turning into a null reference one layer up.

Localization and label format. Labels come back in formats that expect specific printer/page assumptions; decide early whether you're returning a PDF URL, a byte stream, or a base64 blob, and store it, not the temporary path. Same for the return/back-label if you use it.

Extension points. The client is bound in the service provider, so you can rebind an interface in your own provider to inject a mock for tests, or to decorate the client with logging/retry. For testing, swap the binding with a fake returning fixture payloads — do not hit Econt in the test suite.

Pin the package version. At ~20 stars this is a small, single-maintainer wrapper; the Econt API and this library both move. Pin a minor version in composer.json, read the diff on upgrade, and keep your own mapping layer thin enough that a breaking change is a one-file fix.

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route