Appearance
Orders
Create and manage delivery orders. An order ships a package from one of your branches to a customer's address.
List orders
GET /integration/merchant/order
Returns a paginated list of your orders. Useful for reconciliation and dashboards.
Query parameters (all optional):
| Parameter | Type | Notes |
|---|---|---|
page | number | Page number (default 1). |
limit | number | Items per page (default 20, max 100). |
status | string | Filter by status. Defaults to all statuses except cancelled. |
dateFrom / dateTo | ISO date | Filter by creation date range. |
referenceNumber | string | Filter by your orderMerchantReferenceNumber. |
sandbox | 1 | Include only sandbox orders. |
Response: 200 OK
json
{
"success": true,
"data": {
"list": [ /* order objects */ ],
"pagination": { "page": 1, "limit": 20, "total": 42 }
}
}Create an order
POST /integration/merchant/order
Request body:
json
{
"customerId": "<customer-id>",
"customerAddressId": "<address-id>",
"branchCode": "MAIN",
"specialHandlingTags": ["none"],
"paymentMethod": "cod",
"amountToCollect": 12.500,
"pricing": { "subtotal": 11.000, "deliveryFee": 1.500, "total": 12.500 },
"items": [
{ "name": "T-Shirt", "sku": "TS-01", "qty": 2, "price": 5.500 }
],
"merchantNotes": "Leave at reception",
"orderMerchantReferenceNumber": "WEB-10042"
}| Field | Required | Notes |
|---|---|---|
customerId | Yes | A customer that belongs to your merchant. |
customerAddressId | No | Which address to deliver to. Defaults to the customer's default address. |
branchId or branchCode | Yes | The pickup branch. Use either the branch's _id or its code. |
specialHandlingTags | Yes | Array; at least one tag required. Use ["none"] if nothing special. Allowed: fragile, liquid, heavy, oversized, temperature_sensitive, food, flowers, other, none. |
paymentMethod | No | cod or prepaid (default). |
amountToCollect | COD only | Required and non-negative for COD. Cannot exceed pricing.total. |
pricing | No | { subtotal, deliveryFee, total }. If deliveryFee is omitted, Wasal resolves it automatically from your pricing zones for the delivery area. |
items | No | Line items: { name, sku, qty, price }. |
merchantNotes | No | Internal note shown to the driver. |
agentNotes | No | Note for the delivery agent. |
orderMerchantReferenceNumber | No | Your own reference (e.g. ecommerce order number). Echoed back and used for reconciliation. |
packageSide | No | One of front, back, left, right, top, bottom, other. |
packagePhotoUrls | No | Array of photo URLs. Required if your merchant has requirePackagePhoto enabled. |
scheduledPickupAt, scheduledDeliveryAt | No | ISO timestamps. |
forceDraft | No | true saves the order as a draft regardless of the order window. |
Response: 201 Created
json
{
"success": true,
"data": {
"order": { "_id": "665f...", "orderNumber": "MAIN-000123", "status": "pending" }
}
}Order window & drafts. If the delivery partner's order window is closed (or you pass
forceDraft: true), the order is created as adraftand is not dispatched until activated. Otherwise it enters the live queue immediately.
Wallet. Production orders deduct the delivery fee from your Wasal wallet. If the balance is insufficient you receive
400 INSUFFICIENT_WALLET_BALANCEwith the required amount and current balance. Sandbox orders never touch the wallet.
Get an order
GET /integration/merchant/order/:orderId
Returns the full order document — status, customer snapshot, pricing, items, assigned agent (if any), and timestamps.
Update an order
PUT /integration/merchant/order/:orderId
Updates mutable fields on a draft or pending order. Only the fields you send are changed; all others remain unchanged.
Editable fields:
| Field | Notes |
|---|---|
merchantNotes | Internal note for the driver. |
agentNotes | Note for the delivery agent. |
orderMerchantReferenceNumber | Your reference number. |
items | Replaces the full items array. |
pricing | { subtotal, deliveryFee, total }. |
paymentMethod | cod or prepaid. |
amountToCollect | COD amount. |
scheduledPickupAt, scheduledDeliveryAt | ISO timestamps. |
Response: 200 OK — updated order object.
Activate a draft order
PUT /integration/merchant/order/:orderId/activate
Dispatches a draft order into the live queue. The order window must be open at the time of activation.
Response: 200 OK — order with status: "pending".
Returns
400 ORDER_WINDOW_CLOSEDif the delivery partner's order window is not currently open.
Cancel an order
PUT /integration/merchant/order/:orderId/cancel
Cancels an order that has not yet been delivered. Sets the status to cancelled and records the cancellation timestamp.
Order status history
GET /integration/merchant/order/:orderId/history
Returns the chronological statusHistory[] — each entry includes the status, timestamp, an optional note, and who made the change. Use this to render a timeline.
Agent live location
GET /integration/merchant/order/:orderId/agent-location
Returns the assigned agent's latest location while the order is in transit. Returns no location if no agent is assigned, the agent is offline, or the order is not in an active delivery status.
Shipping label
GET /integration/merchant/order/:orderId/label
Returns a printable PDF shipping label for the order. The response Content-Type is application/pdf.
Order lifecycle
| Status | Meaning |
|---|---|
draft | Created but not yet dispatched (order window closed or forceDraft). |
pending | In the live queue, awaiting a driver. |
assigned | A driver has accepted the order. |
on_way_to_merchant | Driver is heading to your branch for pickup. |
picked_up | Driver has collected the package. |
in_transit | En route to the customer. |
delivered | Successfully delivered (terminal). |
failed | Delivery failed (terminal). |
returned | Returned to merchant (terminal). |
cancelled | Cancelled (terminal). |
In the sandbox, you advance these statuses yourself via the advance-status endpoint. In production, real drivers move the order and you observe the changes via polling or webhooks.
Errors
| HTTP | code | Meaning |
|---|---|---|
| 400 | CUSTOMER_REQUIRED | customerId missing. |
| 400 | SPECIAL_HANDLING_REQUIRED | specialHandlingTags empty. |
| 400 | INVALID_SPECIAL_HANDLING_TAG | A tag is not in the allowed list. |
| 400 | INVALID_PACKAGE_SIDE | packageSide not in the allowed list. |
| 400 | INVALID_AMOUNT_TO_COLLECT | COD amount missing or negative. |
| 400 | AMOUNT_EXCEEDS_TOTAL | COD amount greater than pricing.total. |
| 400 | PACKAGE_PHOTO_REQUIRED | Merchant requires a package photo. |
| 400 | VALIDATION_FAILED | Other field errors — see errors. |
| 400 | INSUFFICIENT_WALLET_BALANCE | Wallet cannot cover the delivery fee (production only). |
| 400 | ORDER_NOT_DRAFT | Activate was called on an order that is not a draft. |
| 400 | ORDER_WINDOW_CLOSED | Activate was called outside the delivery partner's order window. |
| 404 | CUSTOMER_NOT_FOUND | Customer not found or not linked to your merchant. |
| 404 | CUSTOMER_NO_DELIVERY_ADDRESS | Customer has no address. |
See the full Error Reference.
