dinas/shipping-sdk-laravel
Laravel SDK for the Dinas Shipping API. Send requests to REST endpoints and receive/verify incoming webhooks. Webhook events are logged and dispatched as Laravel jobs for async updates like shipment status changes and document availability.
Installation:
composer require dinas/shipping-sdk-laravel
Add to .env:
DINAS_SHIPPING_TOKEN=your_api_token
DINAS_SHIPPING_SECRET=your_webhook_secret
Webhook Route:
Add to routes/api.php:
Route::dinasShippingWebhooks('dinas-shipping/webhook');
CSRF Exclusion:
Update app/Providers/AppServiceProvider.php:
protected $except = ['dinas-shipping/webhook'];
Publish Config/Migrations:
php artisan vendor:publish --provider="Dinas\Shipping\ShippingServiceProvider" --tag="shipping-sdk-laravel-config"
php artisan vendor:publish --tag="shipping-sdk-laravel-migrations"
php artisan migrate
Register Webhook:
php artisan webhook:dinas-shipping -i
Fetch pending cars with photos:
use Dinas\Shipping\Facades\Shipping;
$cars = Shipping::getCars([
'status' => \Dinas\ShippingSdk\Model\StockStatus::PENDING,
'photos' => true
]);
foreach ($cars->getData() as $car) {
echo $car->getChassis() . ': ' . $car->getMake();
}
Fetch Data:
$cars = Shipping::getCars(['status' => 'pending']);
$voyage = Shipping::getVoyage(123);
Create/Update:
// Sync cars (upsert)
Shipping::syncCars([['chassis' => 'ABC123', 'make' => 'Toyota']]);
// Async operations with callbacks
$result = Shipping::storeCarPhotos([...], onResolve: fn($ctx) => {
if ($ctx->isFailed()) Log::error($ctx->message);
});
Status Management:
// Hold/release cars
Shipping::holdCars(['ABC123'], ['date' => '2026-03-15']);
Shipping::releaseCars(['ABC123']);
// Withhold/grant
Shipping::withholdCars(['ABC123'], 'Payment pending');
Shipping::grantCars(['ABC123']);
Jobs Queue:
Async operations (e.g., storeCarPhotos) dispatch Laravel jobs. Handle failures in FailedJob handler:
public function handle(ShouldQueue $job, array $data)
{
if ($job instanceof \Dinas\Shipping\Jobs\StoreCarPhotosJob) {
Log::error('Photo upload failed', $data);
}
}
Events:
Listen to ShippingJobResolved for real-time updates:
event(new ShippingJobResolved($jobId, 'storeCarPhotos', 'finished'));
Broadcasting: Enable Pusher for frontend notifications:
// config/dinas-shipping-sdk.php
'broadcasting' => ['enabled' => true],
Frontend (Laravel Echo):
Echo.private(`user.${userId}`)
.listen('.shipping.job.resolved', (e) => {
console.log('Job resolved:', e);
});
Chunked Uploads: Photos/documents are uploaded in chunks (default: 50 items). Customize in config:
'chunk_size' => 25,
Error Handling:
Validate StoreResult objects:
$result = Shipping::storeCarPhotos([...]);
if (!$result->ok) {
foreach ($result->validationErrors as $field => $messages) {
// Handle per-field errors
}
}
For advanced use cases, access underlying APIs:
$carsApi = Shipping::cars();
$photos = $carsApi->getCarPhotos(chassis: 'ABC123', photos: true);
Webhook Verification:
DINAS_SHIPPING_SECRET matches the API’s registered secret.php artisan webhook:dinas-shipping:test.Async Job Callbacks:
webhook_jobs table. Prune old entries to avoid bloat:
php artisan model:prune --model="Dinas\Shipping\Models\WebhookJob"
WebhookJobContext::isFailed() to distinguish failures.Rate Limiting:
use Dinas\Shipping\Exceptions\RateLimitExceeded;
try {
$result = Shipping::getCars([...]);
} catch (RateLimitExceeded $e) {
sleep($e->retryAfter);
retry();
}
File Uploads:
upload_max_filesize in php.ini (e.g., 20M for large documents).Time Zones:
valid_until) are in UTC. Convert local dates explicitly:
use Carbon\Carbon;
$validUntil = Carbon::now()->addDays(30)->toDateTimeString();
Log Webhook Payloads:
Enable debug logging in config/dinas-shipping-sdk.php:
'debug' => [
'log_webhooks' => true,
],
Logs appear in storage/logs/laravel.log.
Test Webhooks Locally:
Use the webhook:dinas-shipping:test command to simulate webhooks:
php artisan webhook:dinas-shipping:test --event="api.job" --payload='{"job_id": "123"}'
Inspect API Responses:
Enable HTTP logging in config/dinas-shipping-sdk.php:
'http' => [
'debug' => true,
],
Custom HTTP Client: Override the default Guzzle client:
Shipping::setHttpClient(app(\Illuminate\Http\Client\PendingRequest::class));
Webhook Middleware:
Add middleware to app/Providers/WebhookServiceProvider.php:
public function boot()
{
\Spatie\WebhookClient\WebhookClient::useMiddleware(\App\Middleware\ValidateSignature::class);
}
Event Listeners:
Extend webhook handling by listening to WebhookReceived:
public function handle(WebhookReceived $event)
{
if ($event->payload['event'] === 'api.job') {
// Custom logic for job events
}
}
API Response Transformers: Modify responses globally by binding a transformer:
Shipping::bindTransformer(\Dinas\ShippingSdk\Model\Car::class, \App\Transformers\CarTransformer::class);
Chunk Size:
Adjust config/dinas-shipping-sdk.php for large batches:
'chunk_size' => 50, // Default
Broadcasting: Disable if not using Pusher:
'broadcasting' => ['enabled' => false],
Webhook Retries:
Configure retry logic in config/webhook-client.php:
'retries' => 3,
'delay' => 60, // seconds
Caching: Cache frequent API calls (e.g., voyages) using Laravel’s cache:
$voyages = Cache::remember('voyages', now()->addHours(1), function () {
return Shipping::getVoyages();
});
Batch Processing:
Use Laravel’s chunk() for large datasets:
Shipping::getCars(['per_page' => 1000])->chunk(100, function ($cars) {
foreach ($cars as $car) {
// Process in batches
}
});
Queue Workers: Scale async jobs with multiple queue workers:
How can I help you explore Laravel packages today?