Order Bulk Operations
The Orders module supports high-volume operations through queued jobs with progress tracking, cancellation support, and PostgreSQL-optimized batch processing.
CSV Import
Starting an Import
POST /api/v1/orders/bulk/import
Content-Type: multipart/form-data
file: orders.csv
source: csv-import
Response:
{
"data": {
"id": "uuid",
"source": "csv-import",
"status": "processing",
"total_rows": 500,
"processed_rows": 0
}
}
CSV Format
| Column | Required | Description |
|---|---|---|
order_number |
No | Custom order number (auto-generated if empty) |
customer_phone |
Yes* | Customer phone (*or email required) |
customer_email |
Yes* | Customer email (*or phone required) |
customer_first_name |
No | Customer first name |
customer_last_name |
No | Customer last name |
item_name |
Yes | Product name |
item_quantity |
Yes | Quantity |
item_price |
Yes | Unit price |
item_sku |
No | Product SKU |
total |
No | Order total (auto-calculated if empty) |
payment_status |
No | Payment status (default: pending) |
status |
No | Order status (default: pending) |
notes |
No | Order notes |
Checking Import Status
GET /api/v1/orders/bulk/import/{importId}
{
"data": {
"id": "uuid",
"status": "processing",
"total_rows": 500,
"processed_rows": 250,
"created_count": 240,
"updated_count": 5,
"skipped_count": 3,
"error_count": 2,
"errors": [
{ "row": 45, "message": "Missing customer phone/email" },
{ "row": 128, "message": "Invalid payment_status value" }
]
}
}
Import progress is also broadcast via Laravel Reverb for real-time UI updates.
Cancelling an Import
POST /api/v1/orders/bulk/import/{importId}/cancel
Sets import status to cancelled. The background job checks this flag between chunks and stops processing.
Processing Details
- CSV is parsed and processed in 500-row chunks
- Each chunk runs through the
OrderIngestServicefor proper validation and event publishing - Uses PostgreSQL
INSERT ... ON CONFLICT DO UPDATEfor idempotent upserts - Queued on the
importsqueue (configure a dedicated Horizon supervisor)
CSV Export
Starting an Export
POST /api/v1/orders/bulk/export
{
"filters": {
"status": "delivered",
"date_from": "2026-01-01",
"date_to": "2026-03-01"
},
"columns": ["order_number", "customer_name", "total", "status", "created_at"]
}
Downloading the Export
GET /api/v1/orders/bulk/export/{exportId}/download
Returns the CSV file. Exports use cursor-based streaming for memory efficiency — even millions of orders won't exhaust server memory.
Bulk Status Update
Update multiple orders' status in a single request:
POST /api/v1/orders/bulk/status
{
"order_ids": ["uuid1", "uuid2", "uuid3"],
"status": "confirmed",
"reason": "Payment verified"
}
Internally uses a single UPDATE ... WHERE id IN (...) SQL query plus batch-inserted status history records for performance.
Bulk Ship
Create shipments for multiple orders at once:
POST /api/v1/orders/bulk/ship
{
"shipments": [
{
"order_id": "uuid1",
"carrier_module": "shipping-delhivery",
"awb_number": "DLV123456",
"tracking_url": "https://track.delhivery.com/DLV123456"
},
{
"order_id": "uuid2",
"carrier_module": "shipping-delhivery",
"awb_number": "DLV123457",
"tracking_url": "https://track.delhivery.com/DLV123457"
}
]
}
Bulk Cancel
Cancel multiple orders at once:
POST /api/v1/orders/bulk/cancel
{
"order_ids": ["uuid1", "uuid2"],
"reason": "Out of stock"
}
Only cancels orders in cancellable statuses (pending, confirmed, processing).
Queue Configuration
Add dedicated supervisors in config/horizon.php:
'environments' => [
'production' => [
'supervisor-imports' => [
'connection' => 'redis',
'queue' => ['imports'],
'maxProcesses' => 2,
'timeout' => 600,
],
'supervisor-exports' => [
'connection' => 'redis',
'queue' => ['exports'],
'maxProcesses' => 2,
'timeout' => 300,
],
],
],