Create multiple shipments asynchronously (NDJSON)
Queues a background job that creates shipments from a Newline-Delimited JSON (NDJSON) file. Each line in the file is a single shipment object â blank lines are ignored.
The endpoint returns immediately with a jobId.
Poll GET /api/create-shipment/bulk/status/{jobId} to track progress.
Maximum 500 shipments per request.
How to uploadâ
Send a multipart/form-data request containing:
| Form field | Required | Description |
|---|---|---|
shipments | â | The .ndjson file. The server identifies it by field name shipments or by .ndjson file extension. |
cmpService | â | Service type: DELIVERY or REVERSE. Applied to all rows in the batch. |
subAccountId | â | UUID of the sub-account. Optional when authenticating via API key. |
locationId | â | Pickup location ID. When provided every shipment starts as AWAITING_PICKUP and a pickup request is auto-created. When absent shipments start as NEW. |
NDJSON Row Schema â one JSON object per lineâ
Each line in the uploaded .ndjson file represents a single shipment.
Blank lines and BOM-prefixed first lines are silently skipped.
The file must be UTF-8 encoded.
â Required fieldsâ
| Field | Type | Validation | Description |
|---|---|---|---|
consigneeName | string | max 255 | Full name of the recipient / consignee. |
consigneePhone | string | E.164 â +[1-9]\d{6,14} | Primary phone of the recipient. Example: +201001234567 |
governorateId | integer | âĨ 1 | Destination governorate ID. Omit only if districtId is provided â the server auto-fills this from the district. |
cityId | integer | âĨ 1 | Destination city ID â drives branch routing. Omit only if districtId is provided. |
addressText or structured parts | string / parts | â | Free-text delivery address. Optional when streetName or buildingNumber is present â the server builds addressText from the parts automatically. |
đ District auto-resolutionâ
If only districtId is sent (without cityId/governorateId), the server resolves
both values from the district record before validation, so no extra round-trip is needed
from the client.
đ Shipment dimensionsâ
| Field | Type | Default | Description |
|---|---|---|---|
weight | number | 0 | Gross weight in kg. Chargeable = max(weight, WÃHÃL / 5000). |
length | number | 0 | Length in cm. |
width | number | 0 | Width in cm. |
height | number | 0 | Height in cm. |
noOfPcs | integer | 1 | Total pieces (âĨ 1). |
đ¤ Consignee contact detailsâ
| Field | Type | Description |
|---|---|---|
attentionTo | string (max 255) | Attention-to / care-of name. |
consigneePhoneAlt | string (E.164) | Alternate phone. |
consigneePhoneAlt2 | string (E.164) | Second alternate phone. |
consigneeEmail | string (max 255) | Consignee email address. |
nationalId | string (max 50) | National ID for identity-verified delivery. |
districtId | integer | Destination district ID. When sent without cityId/governorateId both are resolved automatically. |
consigneeNotes | string | Delivery notes shown to the courier. |
latitude | number (max 6dp) | GPS latitude. |
longitude | number (max 6dp) | GPS longitude. |
đ Structured address componentsâ
Address resolution pyramid:
- If
streetNameorbuildingNumberis present â the server buildsaddressTextfrom the structured parts (auto-detects Arabic vs English) and ignores anyaddressTextyou sent. - Otherwise â the provided
addressTextis used as-is.
newAddressText is independent â stored as a secondary address on the consignee and does not affect the pyramid.
| Field | Type | Description |
|---|---|---|
streetName | string (max 255) | Street name â triggers pyramid when present. |
buildingNumber | string (max 255) | Building/house number â triggers pyramid when present. |
floor | string (max 255) | Floor number. |
apartment | string (max 255) | Apartment / unit number. |
landmarkNearby | string (max 255) | Nearby landmark for courier guidance. |
newAddressText | string | Optional secondary address. Stored independently on the consignee. |
đ Shipment metadataâ
| Field | Type | Description |
|---|---|---|
ref | string (max 255) | Your internal order or reference number. |
packageType | PARCEL | DOCUMENTS | BULKY | Packaging type â drives handling rules. |
contents | string (max 500) | Description of the shipment contents. |
itemValue | number (âĨ 0) | Declared value in EGP â used for insurance. |
cash | number (âĨ 0) | Cash-on-delivery (COD) amount in EGP. Zero = no COD. |
specialInstructions | string (max 500) | Special handling instructions. |
productId | integer (âĨ 1) | Product type ID. Overridden by the form-level productId if that is supplied. |
shipmentServiceIds | integer[] | Add-on service IDs. Fetch from GET /create-shipment/all-services. |
đ AWB and backdatingâ
| Field | Type | Description |
|---|---|---|
awb | string | Manual AWB override. Auto-generated when omitted. Duplicate AWBs are skipped and reported in the skipped array. |
âŠī¸ Return locationâ
| Field | Type | Description |
|---|---|---|
returnLocationId | integer (âĨ 1) | Location to which the shipment is returned on delivery failure. Defaults to the sub-account warehouse. The server derives returnBranchId from this location automatically. |
đĻ Sub-packages breakdownâ
Use packages when a single shipment contains multiple pieces with different dimensions:
"packages": [
{ "quantity": 2, "weight": 3.5, "length": 30, "width": 20, "height": 15 },
{ "quantity": 1, "weight": 0.8, "length": 20, "width": 10, "height": 10 }
]
đ International shipment dataâ
"createInternationalData": {
"purposeOfShipment": "COMMERCIAL_SAMPLE",
"hsCode": "6109.10",
"madeInId": 1
}
đĢ Server-derived fields â do NOT include in the NDJSONâ
| Field | Derived from |
|---|---|
businessLocationId | Sub-account warehouse (or locationId form field). |
returnBranchId | Branch of the resolved returnLocationId. |
deliveryBranchId | Branch of cityId (DELIVERY) or warehouse branch (REVERSE). |
currentBranchId | Always null at creation. |
fromBranchId | Always null at creation. |
â ī¸ REVERSE shipment notesâ
When cmpService = REVERSE (the form field â not per-row):
- The customer's flat address data (
streetName,buildingNumber,addressText, etc.) becomes an ad-hoc pickup origin (fromLocationId). - Consignee = the merchant â the sub-account name + warehouse address is stored as the consignee.
returnLocationIdâ should be the merchant warehouse (or omit to default to it).
đ Minimal valid NDJSON examplesâ
DELIVERY â districtId only (server resolves city + governorate):
{"consigneeName":"Ahmed Hassan","consigneePhone":"+201001234567","districtId":1,"addressText":"15 Ø´Ø§ØąØš اŲŲØĩØąØ Ø´ŲØŠ 4Ø Ų
دŲŲØŠ ŲØĩØą","weight":2.5,"length":30,"width":20,"height":15,"cash":250,"ref":"ORD-001","packageType":"PARCEL","contents":"Ų
ŲØ§Ø¨Øŗ","productId":1}
DELIVERY â cityId + structured address:
{"consigneeName":"Mariam Tarek","consigneePhone":"+201223334445","governorateId":2,"cityId":25,"streetName":"Ø´Ø§ØąØš Ø§ŲØŦŲØ§ØĄ","buildingNumber":"18","floor":"3","apartment":"12","landmarkNearby":"ØŖŲ
اŲ
Ų
ØŗØŦد اŲŲŲØą","weight":0.5,"cash":0,"ref":"ORD-002","packageType":"DOCUMENTS","productId":1}
REVERSE â with explicit return location:
{"consigneeName":"Khaled Mohamed","consigneePhone":"+201501112233","governorateId":1,"cityId":10,"addressText":"45 Ø´Ø§ØąØš اŲŲØąŲ
Ø Ø§ŲØŦŲØ˛ØŠ","weight":1.5,"length":25,"width":15,"height":10,"cash":0,"ref":"RTN-001","packageType":"PARCEL","returnLocationId":7,"productId":1}
Requestâ
Responsesâ
201 Created
Job enqueued. Poll trackingUrl for progress.
400 Bad Request
Validation error â malformed JSON, missing required fields, invalid enum, or > 500 rows. The message array contains per-row error details.
401 Unauthorized
Unauthorized.
404 Not Found
Sub-account or pickup location not found.
500 Internal Server Error
Internal Server Error.