PHPackages                             terminaldz/laravel-yalidine - 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. terminaldz/laravel-yalidine

ActiveLibrary[API Development](/categories/api)

terminaldz/laravel-yalidine
===========================

Laravel package for integrating with the Yalidine delivery API

10PHP

Since Oct 9Pushed 7mo agoCompare

[ Source](https://github.com/TerminalDZ/Laravel-Yalidine)[ Packagist](https://packagist.org/packages/terminaldz/laravel-yalidine)[ RSS](/packages/terminaldz-laravel-yalidine/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

Laravel Yalidine
================

[](#laravel-yalidine)

[![Latest Version on Packagist](https://camo.githubusercontent.com/75a12de5ad25b8643c54d5dbea0bbab516b3908406474d4776a3b4d7cba668ba/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7465726d696e616c647a2f6c61726176656c2d79616c6964696e652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/terminaldz/laravel-yalidine)[![Total Downloads](https://camo.githubusercontent.com/4c619449ca8b8b264a199ea723fc76950f45ae8d4ff8c9a36bd2fd6ad12712e6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7465726d696e616c647a2f6c61726176656c2d79616c6964696e652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/terminaldz/laravel-yalidine)[![License](https://camo.githubusercontent.com/94e8eb3702e5a8283ced69ac345fde980da97e2b34f3d48a0fa41691faafa1e0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7465726d696e616c647a2f6c61726176656c2d79616c6964696e652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/terminaldz/laravel-yalidine)

A Laravel package for integrating with the Yalidine delivery API. This package provides a clean, fluent interface for managing parcels, tracking shipments, retrieving location data, and calculating delivery fees through the Yalidine REST API.

Features
--------

[](#features)

- 🚀 Simple and intuitive API
- 📦 Complete parcel management (create, retrieve, update, delete)
- 📍 Location data retrieval (wilayas, communes, centers)
- 📊 Delivery history tracking
- 💰 Fee calculation with weight and dimension support
- ⚡ Rate limit handling and monitoring
- 🔄 Pagination support for large datasets
- ✅ Comprehensive validation
- 🧪 Testing utilities included
- 📝 Full Laravel integration (Service Provider, Facade, DI)
- 🔒 Secure credential management
- 📋 Detailed error messages and exceptions

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

[](#requirements)

- PHP &gt;= 8.1
- Laravel &gt;= 10.0
- Guzzle &gt;= 7.0

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

[](#installation)

Install the package via Composer:

```
composer require terminaldz/laravel-yalidine
```

### Publish Configuration

[](#publish-configuration)

Publish the configuration file:

```
php artisan vendor:publish --provider="Terminaldz\LaravelYalidine\YalidineServiceProvider"
```

This will create a `config/yalidine.php` configuration file.

### Environment Variables

[](#environment-variables)

Add your Yalidine API credentials to your `.env` file:

```
YALIDINE_API_ID=your_api_id_here
YALIDINE_API_TOKEN=your_api_token_here
YALIDINE_BASE_URL=https://api.yalidine.app/v1
```

You can obtain your API credentials from your Yalidine dashboard.

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

[](#configuration)

The `config/yalidine.php` file contains all configuration options:

```
return [
    // API Credentials
    'api_id' => env('YALIDINE_API_ID'),
    'api_token' => env('YALIDINE_API_TOKEN'),
    'base_url' => env('YALIDINE_BASE_URL', 'https://api.yalidine.app/v1'),

    // HTTP Client Options
    'timeout' => env('YALIDINE_TIMEOUT', 30),
    'retry_times' => env('YALIDINE_RETRY_TIMES', 3),
    'retry_delay' => env('YALIDINE_RETRY_DELAY', 1000),

    // Rate Limit Settings
    'rate_limit' => [
        'log_warnings' => true,
        'warning_threshold' => 10,
    ],

    // Caching
    'cache' => [
        'enabled' => true,
        'ttl' => 3600,
        'prefix' => 'yalidine',
    ],

    // Logging
    'logging' => [
        'enabled' => env('YALIDINE_LOGGING', true),
        'channel' => env('YALIDINE_LOG_CHANNEL', 'stack'),
    ],
];
```

Basic Usage
-----------

[](#basic-usage)

### Using the Facade

[](#using-the-facade)

```
use Terminaldz\LaravelYalidine\Facades\Yalidine;

// Create a parcel
$result = Yalidine::parcels()->create([
    'order_id' => 'ORDER-12345',
    'from_wilaya_name' => 'Alger',
    'firstname' => 'Ahmed',
    'familyname' => 'Benali',
    'contact_phone' => '0550123456',
    'address' => 'Cité des Martyrs, Bâtiment A',
    'to_commune_name' => 'Bordj El Kiffan',
    'to_wilaya_name' => 'Alger',
    'product_list' => 'Electronics - Smartphone',
    'price' => 5000,
    'do_insurance' => true,
    'declared_value' => 5000,
    'length' => 30,
    'width' => 20,
    'height' => 10,
    'weight' => 2,
    'freeshipping' => false,
    'is_stopdesk' => false,
    'has_exchange' => false,
]);

echo "Tracking Number: " . $result->tracking;
echo "Label URL: " . $result->label;
```

### Using Dependency Injection

[](#using-dependency-injection)

```
use Terminaldz\LaravelYalidine\Client\YalidineClient;

class ShippingController extends Controller
{
    public function __construct(
        private YalidineClient $yalidine
    ) {}

    public function createShipment(Request $request)
    {
        $result = $this->yalidine->parcels()->create([
            'order_id' => $request->order_id,
            'firstname' => $request->firstname,
            'familyname' => $request->familyname,
            // ... other fields
        ]);

        return response()->json([
            'tracking' => $result->tracking,
            'label' => $result->label,
        ]);
    }
}
```

Usage Examples
--------------

[](#usage-examples)

### Parcel Management

[](#parcel-management)

#### Create a Single Parcel

[](#create-a-single-parcel)

```
$result = Yalidine::parcels()->create([
    'order_id' => 'ORDER-12345',
    'from_wilaya_name' => 'Alger',
    'firstname' => 'Ahmed',
    'familyname' => 'Benali',
    'contact_phone' => '0550123456',
    'address' => 'Cité des Martyrs',
    'to_commune_name' => 'Bordj El Kiffan',
    'to_wilaya_name' => 'Alger',
    'product_list' => 'Electronics',
    'price' => 5000,
    'do_insurance' => true,
    'declared_value' => 5000,
    'length' => 30,
    'width' => 20,
    'height' => 10,
    'weight' => 2,
    'freeshipping' => false,
    'is_stopdesk' => false,
    'has_exchange' => false,
]);
```

#### Create Multiple Parcels (Batch)

[](#create-multiple-parcels-batch)

```
$parcels = [
    [
        'order_id' => 'ORDER-001',
        'firstname' => 'Ahmed',
        // ... other fields
    ],
    [
        'order_id' => 'ORDER-002',
        'firstname' => 'Fatima',
        // ... other fields
    ],
];

$results = Yalidine::parcels()->createBatch($parcels);
```

#### Retrieve a Parcel

[](#retrieve-a-parcel)

```
$parcel = Yalidine::parcels()->get('yal-123456');

echo $parcel->tracking;
echo $parcel->lastStatus;
echo $parcel->dateCreation->format('Y-m-d H:i');
```

#### List Parcels with Filters

[](#list-parcels-with-filters)

```
$parcels = Yalidine::parcels()->list([
    'status' => 'Livré',
    'wilaya' => 16,
    'from_date' => '2025-01-01',
    'to_date' => '2025-01-31',
    'page' => 1,
    'page_size' => 50,
]);

foreach ($parcels->items() as $parcel) {
    echo $parcel->tracking . ': ' . $parcel->lastStatus . "\n";
}

if ($parcels->hasNextPage()) {
    $nextUrl = $parcels->getNextPageUrl();
}
```

#### Update a Parcel

[](#update-a-parcel)

```
// Only parcels with status "en préparation" can be updated
$parcel = Yalidine::parcels()->update('yal-123456', [
    'contact_phone' => '0551234567',
    'address' => 'New Address',
]);
```

#### Delete a Parcel

[](#delete-a-parcel)

```
// Only parcels with status "en préparation" can be deleted
$deleted = Yalidine::parcels()->delete('yal-123456');
```

### Location Data

[](#location-data)

#### Get All Wilayas

[](#get-all-wilayas)

```
$wilayas = Yalidine::locations()->wilayas();

foreach ($wilayas->items() as $wilaya) {
    echo $wilaya->id . ': ' . $wilaya->name . "\n";
}
```

#### Get Communes for a Wilaya

[](#get-communes-for-a-wilaya)

```
$communes = Yalidine::locations()->communes([
    'wilaya_id' => 16,
]);

foreach ($communes->items() as $commune) {
    echo $commune->name . ' - Delivery time: ' . $commune->deliveryTimeParcel . ' days' . "\n";
}
```

#### Get Communes with Stop Desks

[](#get-communes-with-stop-desks)

```
$stopDeskCommunes = Yalidine::locations()->communes([
    'wilaya_id' => 16,
    'has_stop_desk' => true,
]);
```

#### Get Centers

[](#get-centers)

```
$centers = Yalidine::locations()->centers([
    'wilaya_id' => 16,
    'commune_id' => 1630,
]);

foreach ($centers->items() as $center) {
    echo $center->name . ' - ' . $center->address . "\n";
    echo 'GPS: ' . $center->getLatitude() . ', ' . $center->getLongitude() . "\n";
}
```

### Delivery History

[](#delivery-history)

#### Get History for a Parcel

[](#get-history-for-a-parcel)

```
$history = Yalidine::histories()->get('yal-123456');

foreach ($history as $status) {
    echo $status->dateStatus->format('Y-m-d H:i') . ': ';
    echo $status->status;

    if ($status->reason) {
        echo ' (' . $status->reason . ')';
    }

    echo "\n";
}
```

#### List Histories with Filters

[](#list-histories-with-filters)

```
$histories = Yalidine::histories()->list([
    'tracking' => 'yal-123456',
    'status' => 'Livré',
    'from_date' => '2025-01-01',
    'to_date' => '2025-01-31',
]);
```

### Fee Calculation

[](#fee-calculation)

#### Calculate Fees Between Wilayas

[](#calculate-fees-between-wilayas)

```
$fees = Yalidine::fees()->calculate(
    fromWilayaId: 5,  // Batna
    toWilayaId: 16    // Alger
);

echo "Zone: " . $fees->zone . "\n";
echo "COD Percentage: " . $fees->codPercentage . "%\n";
echo "Insurance Percentage: " . $fees->insurancePercentage . "%\n";

// Get fee for a specific commune
$communeFee = $fees->getFeeForCommune(1630);
echo "Express Home: " . $communeFee->expressHome . " DA\n";
echo "Express Stop Desk: " . $communeFee->expressStopDesk . " DA\n";
```

#### Calculate Total Fee Including Weight

[](#calculate-total-fee-including-weight)

```
$total = Yalidine::fees()->calculateTotal([
    'from_wilaya_id' => 5,
    'to_wilaya_id' => 16,
    'commune_id' => 1630,
    'price' => 5000,
    'declared_value' => 5000,
    'weight' => 7,
    'length' => 30,
    'width' => 20,
    'height' => 10,
    'delivery_type' => 'express_home',
]);

echo "Total Fee: " . $total . " DA";
```

### Rate Limit Monitoring

[](#rate-limit-monitoring)

```
$rateLimits = Yalidine::getRateLimitInfo();

echo "Second quota left: " . $rateLimits['second'] . "\n";
echo "Minute quota left: " . $rateLimits['minute'] . "\n";
echo "Hour quota left: " . $rateLimits['hour'] . "\n";
echo "Day quota left: " . $rateLimits['day'] . "\n";
```

Error Handling
--------------

[](#error-handling)

The package provides specific exceptions for different error scenarios:

```
use Terminaldz\LaravelYalidine\Exceptions\ValidationException;
use Terminaldz\LaravelYalidine\Exceptions\RateLimitExceededException;
use Terminaldz\LaravelYalidine\Exceptions\AuthenticationException;
use Terminaldz\LaravelYalidine\Exceptions\YalidineException;

try {
    $result = Yalidine::parcels()->create($parcelData);
} catch (ValidationException $e) {
    // Handle validation errors
    foreach ($e->getErrors() as $field => $errors) {
        echo "$field: " . implode(', ', $errors) . "\n";
    }
} catch (RateLimitExceededException $e) {
    // Handle rate limit
    $retryAfter = $e->getRetryAfter();
    Log::warning("Rate limit exceeded. Retry after {$retryAfter} seconds");
} catch (AuthenticationException $e) {
    // Handle authentication errors
    Log::error('Invalid API credentials: ' . $e->getMessage());
} catch (YalidineException $e) {
    // Handle other Yalidine errors
    Log::error('Yalidine API error: ' . $e->getMessage());
}
```

Testing
-------

[](#testing)

The package includes testing utilities to help you test your integration without making real API calls:

```
use Terminaldz\LaravelYalidine\Facades\Yalidine;
use Terminaldz\LaravelYalidine\DataTransferObjects\Parcel;

// In your test
Yalidine::fake([
    'parcels.create' => [
        'tracking' => 'yal-TEST123',
        'order_id' => 'ORDER-12345',
        'label' => 'https://example.com/label.pdf',
        'success' => true,
    ],
]);

// Your code that uses Yalidine
$result = Yalidine::parcels()->create([...]);

// Assert expectations
Yalidine::assertParcelCreated();
Yalidine::assertParcelCreated(function ($data) {
    return $data['order_id'] === 'ORDER-12345';
});
```

Advanced Usage
--------------

[](#advanced-usage)

### Fluent Query Builder

[](#fluent-query-builder)

```
$parcels = Yalidine::parcels()
    ->query()
    ->whereStatus('Livré')
    ->whereWilaya(16)
    ->whereDateBetween('2025-01-01', '2025-01-31')
    ->whereOrderId('ORDER-12345')
    ->paginate(50);
```

### Caching Location Data

[](#caching-location-data)

Location data is automatically cached based on your configuration. You can manually clear the cache:

```
// Clear all Yalidine cache
Cache::tags(['yalidine'])->flush();

// Or use the cache prefix from config
$prefix = config('yalidine.cache.prefix');
Cache::forget("{$prefix}:wilayas");
```

Common Use Cases
----------------

[](#common-use-cases)

### E-commerce Integration

[](#e-commerce-integration)

```
// In your order processing logic
public function processOrder(Order $order)
{
    try {
        // Create parcel when order is confirmed
        $result = Yalidine::parcels()->create([
            'order_id' => $order->id,
            'from_wilaya_name' => config('shop.wilaya'),
            'firstname' => $order->customer->first_name,
            'familyname' => $order->customer->last_name,
            'contact_phone' => $order->customer->phone,
            'address' => $order->shipping_address,
            'to_commune_name' => $order->commune,
            'to_wilaya_name' => $order->wilaya,
            'product_list' => $order->items->pluck('name')->implode(', '),
            'price' => $order->total_with_shipping,
            'do_insurance' => $order->total > 10000,
            'declared_value' => $order->total,
            'freeshipping' => $order->has_free_shipping,
        ]);

        // Save tracking number
        $order->update([
            'tracking_number' => $result->tracking,
            'shipping_label_url' => $result->label,
        ]);

        // Notify customer
        $order->customer->notify(new ShipmentCreated($result->tracking));

    } catch (ValidationException $e) {
        Log::error('Invalid order data for Yalidine', [
            'order_id' => $order->id,
            'errors' => $e->getErrors(),
        ]);
        throw $e;
    }
}
```

### Tracking Status Updates

[](#tracking-status-updates)

```
// Create a scheduled job to update parcel statuses
public function handle()
{
    $pendingOrders = Order::whereIn('status', ['shipped', 'in_transit'])->get();

    foreach ($pendingOrders as $order) {
        try {
            $parcel = Yalidine::parcels()->get($order->tracking_number);

            // Update order status based on parcel status
            if ($parcel->lastStatus === 'Livré') {
                $order->markAsDelivered();
                $order->customer->notify(new OrderDelivered($order));
            } elseif (in_array($parcel->lastStatus, ['Échec', 'Retour'])) {
                $order->markAsFailed();
                $order->customer->notify(new DeliveryFailed($order, $parcel->lastStatus));
            }

        } catch (YalidineException $e) {
            Log::warning('Failed to update tracking for order', [
                'order_id' => $order->id,
                'error' => $e->getMessage(),
            ]);
        }
    }
}
```

### Dynamic Fee Calculator

[](#dynamic-fee-calculator)

```
// Calculate shipping fees in real-time during checkout
public function calculateShipping(Request $request)
{
    $validated = $request->validate([
        'wilaya_id' => 'required|integer',
        'commune_id' => 'required|integer',
        'cart_total' => 'required|numeric',
    ]);

    try {
        $fees = Yalidine::fees()->calculate(
            fromWilayaId: config('shop.wilaya_id'),
            toWilayaId: $validated['wilaya_id']
        );

        $communeFee = $fees->getFeeForCommune($validated['commune_id']);

        return response()->json([
            'express_home' => $communeFee->expressHome,
            'express_stopdesk' => $communeFee->expressStopDesk,
            'classic_home' => $communeFee->classicHome,
            'classic_stopdesk' => $communeFee->classicStopDesk,
        ]);

    } catch (YalidineException $e) {
        return response()->json([
            'error' => 'Unable to calculate shipping fees',
        ], 500);
    }
}
```

### Location Dropdown Population

[](#location-dropdown-population)

```
// Populate location dropdowns for checkout form
public function getLocations(Request $request)
{
    // Cache wilayas for 24 hours
    $wilayas = Cache::remember('yalidine:wilayas', 86400, function () {
        return Yalidine::locations()->wilayas()->items();
    });

    // Get communes for selected wilaya
    if ($request->has('wilaya_id')) {
        $communes = Cache::remember(
            "yalidine:communes:{$request->wilaya_id}",
            86400,
            function () use ($request) {
                return Yalidine::locations()->communes([
                    'wilaya_id' => $request->wilaya_id,
                ])->items();
            }
        );

        return response()->json([
            'wilayas' => $wilayas,
            'communes' => $communes,
        ]);
    }

    return response()->json(['wilayas' => $wilayas]);
}
```

Error Handling Patterns
-----------------------

[](#error-handling-patterns)

### Graceful Degradation

[](#graceful-degradation)

```
try {
    $result = Yalidine::parcels()->create($parcelData);
    return redirect()->route('orders.show', $order)->with('success', 'Shipment created');
} catch (ValidationException $e) {
    // Show validation errors to user
    return back()->withErrors($e->getErrors())->withInput();
} catch (RateLimitExceededException $e) {
    // Queue for retry
    CreateYalidineParcel::dispatch($order)->delay(now()->addSeconds($e->getRetryAfter()));
    return back()->with('warning', 'Shipment will be created shortly');
} catch (YalidineException $e) {
    // Log and show generic error
    Log::error('Yalidine API error', ['error' => $e->getMessage()]);
    return back()->with('error', 'Unable to create shipment. Please try again.');
}
```

### Retry Logic with Queues

[](#retry-logic-with-queues)

```
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class CreateYalidineParcel implements ShouldQueue
{
    use InteractsWithQueue, SerializesModels;

    public $tries = 3;
    public $backoff = [60, 300, 900]; // 1 min, 5 min, 15 min

    public function __construct(
        public Order $order
    ) {}

    public function handle()
    {
        try {
            $result = Yalidine::parcels()->create([
                'order_id' => $this->order->id,
                // ... other fields
            ]);

            $this->order->update([
                'tracking_number' => $result->tracking,
                'shipping_label_url' => $result->label,
            ]);

        } catch (RateLimitExceededException $e) {
            // Release back to queue with delay
            $this->release($e->getRetryAfter());
        } catch (ValidationException $e) {
            // Don't retry validation errors
            $this->fail($e);
        }
    }
}
```

### Monitoring Rate Limits

[](#monitoring-rate-limits)

```
// Create a middleware to monitor rate limits
class MonitorYalidineRateLimits
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // Check rate limits after each request
        $rateLimits = Yalidine::getRateLimitInfo();

        // Alert if any quota is running low
        foreach ($rateLimits as $period => $remaining) {
            if ($remaining < 10) {
                Log::warning("Yalidine {$period} quota running low", [
                    'remaining' => $remaining,
                ]);

                // Send alert to admin
                if ($remaining < 5) {
                    Notification::route('slack', config('services.slack.webhook'))
                        ->notify(new YalidineQuotaLow($period, $remaining));
                }
            }
        }

        return $response;
    }
}
```

Validation Rules
----------------

[](#validation-rules)

The package validates data before sending to the API. Here are the validation rules:

### Phone Number Validation

[](#phone-number-validation)

- Mobile: Must start with 0 followed by 9 digits (e.g., 0550123456)
- Landline: Must start with 0 followed by 8 digits (e.g., 021123456)

### Price and Value Validation

[](#price-and-value-validation)

- `price`: Must be between 0 and 150,000 DA
- `declared_value`: Must be between 0 and 150,000 DA

### Dimension Validation

[](#dimension-validation)

- `length`, `width`, `height`: Must be &gt;= 0
- `weight`: Must be &gt;= 0

### Conditional Validation

[](#conditional-validation)

- If `is_stopdesk` is true, `stopdesk_id` is required
- If `has_exchange` is true, `product_to_collect` is required

Performance Tips
----------------

[](#performance-tips)

### 1. Cache Location Data

[](#1-cache-location-data)

Location data (wilayas, communes, centers) rarely changes. Cache it aggressively:

```
// In your AppServiceProvider
public function boot()
{
    // Warm up cache on application boot
    Cache::remember('yalidine:wilayas', 86400, function () {
        return Yalidine::locations()->wilayas()->items();
    });
}
```

### 2. Use Batch Operations

[](#2-use-batch-operations)

When creating multiple parcels, use batch creation:

```
// Instead of this:
foreach ($orders as $order) {
    Yalidine::parcels()->create($order->toParcelData());
}

// Do this:
$parcelsData = $orders->map->toParcelData()->toArray();
Yalidine::parcels()->createBatch($parcelsData);
```

### 3. Queue Heavy Operations

[](#3-queue-heavy-operations)

Queue operations that aren't time-sensitive:

```
// Queue parcel creation
CreateYalidineParcel::dispatch($order);

// Queue status updates
UpdateParcelStatuses::dispatch()->everyFiveMinutes();
```

### 4. Optimize Pagination

[](#4-optimize-pagination)

Use appropriate page sizes based on your needs:

```
// For UI display (smaller pages)
$parcels = Yalidine::parcels()->list(['page_size' => 20]);

// For batch processing (larger pages)
$parcels = Yalidine::parcels()->list(['page_size' => 500]);
```

Troubleshooting
---------------

[](#troubleshooting)

### Authentication Errors

[](#authentication-errors)

**Problem**: Getting 401 Unauthorized errors

**Solution**:

1. Verify your credentials in `.env` file
2. Ensure credentials are published to config: `php artisan config:clear`
3. Check that credentials are correct in Yalidine dashboard

### Rate Limit Errors

[](#rate-limit-errors)

**Problem**: Getting 429 Too Many Requests errors

**Solution**:

1. Implement retry logic with exponential backoff
2. Monitor rate limits using `getRateLimitInfo()`
3. Use queues to spread requests over time
4. Contact Yalidine to increase your quota

### Validation Errors

[](#validation-errors)

**Problem**: Getting validation errors when creating parcels

**Solution**:

1. Check phone number format (0 + 9 digits for mobile)
2. Verify price is within 0-150,000 range
3. Ensure required fields are present
4. Check conditional requirements (stopdesk\_id, product\_to\_collect)

### Connection Timeouts

[](#connection-timeouts)

**Problem**: Requests timing out

**Solution**:

1. Increase timeout in config: `'timeout' => 60`
2. Check your network connection
3. Verify Yalidine API is accessible
4. Use queues for non-critical operations

API Reference
-------------

[](#api-reference)

### Parcel Resource

[](#parcel-resource)

#### `create(array $parcelData): ParcelCreationResult`

[](#createarray-parceldata-parcelcreationresult)

Create a single parcel.

#### `createBatch(array $parcels): array`

[](#createbatcharray-parcels-array)

Create multiple parcels in one request.

#### `get(string $tracking): Parcel`

[](#getstring-tracking-parcel)

Retrieve a parcel by tracking number.

#### `list(array $filters = []): PaginatedResponse`

[](#listarray-filters---paginatedresponse)

List parcels with optional filters.

#### `update(string $tracking, array $data): Parcel`

[](#updatestring-tracking-array-data-parcel)

Update a parcel (only if status is "en préparation").

#### `delete(string $tracking): bool`

[](#deletestring-tracking-bool)

Delete a parcel (only if status is "en préparation").

#### `query(): ParcelQueryBuilder`

[](#query-parcelquerybuilder)

Get a fluent query builder for parcels.

### Location Resource

[](#location-resource)

#### `wilayas(array $filters = []): PaginatedResponse`

[](#wilayasarray-filters---paginatedresponse)

Get all wilayas.

#### `getWilaya(int $id): Wilaya`

[](#getwilayaint-id-wilaya)

Get a specific wilaya by ID.

#### `communes(array $filters = []): PaginatedResponse`

[](#communesarray-filters---paginatedresponse)

Get communes with optional filters (wilaya\_id, has\_stop\_desk).

#### `getCommune(int $id): Commune`

[](#getcommuneint-id-commune)

Get a specific commune by ID.

#### `centers(array $filters = []): PaginatedResponse`

[](#centersarray-filters---paginatedresponse)

Get centers with optional filters (wilaya\_id, commune\_id, center\_id).

#### `getCenter(int $centerId): Center`

[](#getcenterint-centerid-center)

Get a specific center by ID.

### History Resource

[](#history-resource)

#### `get(string $tracking): array`

[](#getstring-tracking-array)

Get delivery history for a specific tracking number.

#### `list(array $filters = []): PaginatedResponse`

[](#listarray-filters---paginatedresponse-1)

List histories with optional filters.

#### `query(): HistoryQueryBuilder`

[](#query-historyquerybuilder)

Get a fluent query builder for histories.

### Fee Resource

[](#fee-resource)

#### `calculate(int $fromWilayaId, int $toWilayaId): FeeCalculation`

[](#calculateint-fromwilayaid-int-towilayaid-feecalculation)

Calculate fees between two wilayas.

#### `calculateTotal(array $parcelSpecs): float`

[](#calculatetotalarray-parcelspecs-float)

Calculate total fee including weight, insurance, and COD.

Documentation
-------------

[](#documentation)

- **[Quick Start Guide](docs/QUICK_START.md)** - Get started in 5 minutes
- **[API Reference](docs/API_REFERENCE.md)** - Complete API reference for all classes and methods
- **[Usage Examples](docs/EXAMPLES.md)** - Practical examples for common use cases
- **[Testing Guide](docs/TESTING.md)** - Comprehensive testing documentation

External Resources
------------------

[](#external-resources)

- [Yalidine Official API Documentation](https://yalidine.app/app/dev/docs/api/index.php)
- [Yalidine Dashboard](https://yalidine.app)

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this package.

Changelog
---------

[](#changelog)

Please see [CHANGELOG.md](CHANGELOG.md) for recent changes.

Security
--------

[](#security)

If you discover any security-related issues, please email  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Terminal DZ](https://github.com/terminaldz)
- [All Contributors](../../contributors)

Support
-------

[](#support)

For issues, questions, or contributions, please visit our [GitHub repository](https://github.com/terminaldz/laravel-yalidine).

License
-------

[](#license)

This package is open-sourced software licensed under the [MIT license](LICENSE.md).

###  Health Score

17

—

LowBetter than 6% of packages

Maintenance45

Moderate activity, may be stable

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity13

Early-stage or recently created project

 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.

### Community

Maintainers

![](https://www.gravatar.com/avatar/6fd0c0bd29b442c64385a617bf913b079e6393482e3aaa750164bea0677de5f0?d=identicon)[terminaldz](/maintainers/terminaldz)

---

Top Contributors

[![TerminalDZ](https://avatars.githubusercontent.com/u/69165137?v=4)](https://github.com/TerminalDZ "TerminalDZ (2 commits)")

### Embed Badge

![Health badge](/badges/terminaldz-laravel-yalidine/health.svg)

```
[![Health](https://phpackages.com/badges/terminaldz-laravel-yalidine/health.svg)](https://phpackages.com/packages/terminaldz-laravel-yalidine)
```

###  Alternatives

[stripe/stripe-php

Stripe PHP Library

4.0k143.3M480](/packages/stripe-stripe-php)[twilio/sdk

A PHP wrapper for Twilio's API

1.6k92.9M272](/packages/twilio-sdk)[knplabs/github-api

GitHub API v3 client

2.2k15.8M187](/packages/knplabs-github-api)[facebook/php-business-sdk

PHP SDK for Facebook Business

90121.9M34](/packages/facebook-php-business-sdk)[meilisearch/meilisearch-php

PHP wrapper for the Meilisearch API

73813.7M114](/packages/meilisearch-meilisearch-php)[google/gax

Google API Core for PHP

263103.1M454](/packages/google-gax)

PHPackages © 2026

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