Orders
Unified order management — create, track, update status, and export orders
Orders
Orders are ingested from any source — delivery apps, marketplaces, web stores, external POS systems, Linkit's till, payment orders and API calls. Each order tracks customer info, line items, totals, status, and fulfillment data.
Keeping up with orders? Don't page through this list on a timer — follow order changes with a cursor (built for polling once a second; an idle poll is a 304), or have them pushed with webhooks.
Read responses (GET /api/v1/orders, GET /api/v1/orders/{id}) always use a single contract: an envelope with spec_version 2026-04-01, event metadata, and a normalized order object (UnifiedOrderPayload). Vendor-native capture may still be stored server-side for ingestion; it is not returned in JSON.
UnifiedOrderPayload (order field)
This is the normalized order inside every read envelope. Field names mirror outbound webhooks.
| Field | Type | Description |
|---|---|---|
id | string | Order record id |
organization_id | string | Tenant id |
source_reference | string | Human or upstream reference |
source_transaction_id | string | Idempotency / upstream transaction key |
source_timestamp | string | Provider timestamp (RFC3339), when known |
destination_id | string | Branch / store id in Linkit |
destination_reference | string | External branch or vendor reference |
order_status | string | Workflow status |
fulfillment_status | string | Fulfillment pipeline |
payment_status | string | Payment pipeline |
fulfillment_method | string | e.g. delivery, pickup, shipping |
payment_method | string | Tender / channel |
currency | string | ISO 4217 |
total_amount | number | Grand total |
discounts_amount | number | Discounts |
vat_amount | number | VAT |
customer_name / customer_phone / customer_email | string | Buyer |
receiver_name / receiver_phone | string | Recipient when different |
skus | string[] | Sku codes when normalized |
products | array | Line items (normalized JSON) |
shipping_address | object | Structured address when present |
order_code | string | Display code |
order_type | string | Order classification |
transport_type | string | Logistics / handoff hint |
comment | string | Notes |
promised_for | string | Scheduled / promise time (RFC3339) |
is_preorder | boolean | Preorder flag |
delivery_fee / service_fee / subtotal | number | Fee breakdown |
store_name | string | Resolved store label |
dispatch_routing | object | Dispatch metadata when present |
shipping_fulfillment | object | Carrier / fulfillment metadata when present |
created_at / updated_at | string | Linkit record times (RFC3339) |
organization_app_id and catalog app_slug live on the parent envelope (see below), not on order — orders.source in storage is the install id (organization_apps row).
Statuses
order_status, payment_status and fulfillment_status are returned exactly as stored, and what is stored depends on the source:
| Source | order_status | payment_status | fulfillment_status |
|---|---|---|---|
| Every connector (HungerStation, Jahez, Salla, Trendyol, …) | RECEIVED, READY_FOR_PICKUP, DISPATCHED, DELIVERED, CANCELLED | pending, paid, refunded, failed, cancelled | Full, Partial, None |
Payment orders (/api/v1/payments/orders) | pending, confirmed | pending, completed | — |
POST /api/v1/orders | whatever you send (non-blank) | pending, processing, completed, failed, refunded | whatever you send (non-blank) |
For one vocabulary across every source, ask for the canonical order (?format=canonical, below): it adds a normalised status (received, ready_for_pickup, dispatched, delivered, cancelled, pending_payment, unknown) and payment.status (pending, paid, refunded, failed, cancelled, unknown) next to the stored values.
List Orders
GET /api/v1/ordersEvery call uses the same authenticated tenant context as the rest of the API: a valid bearer token plus the organization resolved from that token (or an X-Organization-ID override when your account is allowed to access that organization). No additional scopes apply beyond your existing membership and API key rules.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (an invalid value falls back to 1) |
limit | integer | 50 | Items per page, 1–100 (an invalid value falls back to 50) |
status | string | - | Filter by stored order_status (exact match, e.g. DELIVERED) |
payment_status | string | - | Filter by stored payment status |
fulfillment_status | string | - | Filter by stored fulfillment status |
source | string | - | Filter by orders.source — for connector orders this is the install id, not the platform name |
customer_email | string | - | Exact customer email |
currency | string | - | Three-letter code |
min_amount / max_amount | number | - | Bounds on total_amount |
search | string | - | Matches customer name, email, phone, receiver name, order id and source_transaction_id |
from | string | - | Lower bound on created (RFC 3339), e.g. 2026-04-21T00:00:00Z |
to | string | - | Upper bound on created (RFC 3339) |
sort | string | -created | created, total_amount, customer_name, each optionally prefixed with - |
format | string | - | canonical returns canonical orders instead of the envelope below |
include | string | - | With format=canonical: raw adds each order's source payload |
Example Request
curl -X GET "https://linkit.works/api/v1/orders?status=DELIVERED&limit=50" \
-H "Authorization: Bearer your_token_here"Response
{
"spec_version": "2026-04-01",
"event_type": "orders.listed",
"occurred_at": "2026-04-21T10:30:00.123456789Z",
"organization_id": "org_abc123",
"orders": [
{
"spec_version": "2026-04-01",
"event_id": "snapshot-r1234567890abcdef-1713694200123456789",
"event_type": "order.snapshot",
"occurred_at": "2026-04-21T10:30:00.123456789Z",
"organization_id": "org_abc123",
"organization_app_id": "org_app_install_row_id",
"app_slug": "salla-orders",
"order": {
"id": "r1234567890abcdef",
"organization_id": "org_abc123",
"source_reference": "SALLA-ORD-12345",
"source_transaction_id": "TXN-001",
"source_timestamp": "2026-04-21T09:00:00Z",
"destination_id": "store_iv_1",
"destination_reference": "REF-001",
"order_status": "RECEIVED",
"fulfillment_status": "Full",
"payment_status": "paid",
"fulfillment_method": "DELIVERY",
"payment_method": "card",
"currency": "SAR",
"total_amount": 45.65,
"discounts_amount": 0,
"vat_amount": 0,
"customer_name": "Ahmed Hassan",
"products": [],
"created_at": "2026-04-21T09:05:00Z",
"updated_at": "2026-04-21T10:00:00Z"
}
}
],
"pagination": {
"page": 1,
"per_page": 50,
"total_items": 5432,
"total_pages": 109,
"has_next": true,
"has_prev": false
},
"meta": {}
}Canonical format
GET /api/v1/orders?format=canonical answers {spec_version: "2026-09-29", organization_id, orders: [canonical order…], pagination, meta} — the same pagination, one normalised shape for every source. GET /api/v1/orders/{id}?format=canonical answers {spec_version, organization_id, order}. The default (no format) is unchanged.
Get Single Order
GET /api/v1/orders/{id}Uses the same authenticated organization scope as list orders. The body is always one UnifiedOrderEventPayload with event_type order.snapshot (same order object as list rows). Cached hot reads return the same shape.
Example (trimmed)
{
"spec_version": "2026-04-01",
"event_id": "snapshot-r1234567890abcdef-1713694200123456789",
"event_type": "order.snapshot",
"occurred_at": "2026-04-21T10:30:00.123456789Z",
"organization_id": "org_abc123",
"organization_app_id": "org_app_install_row_id",
"app_slug": "salla-orders",
"order": {
"id": "r1234567890abcdef",
"source_reference": "SALLA-ORD-12345",
"source_transaction_id": "TXN-001",
"total_amount": 45.65,
"currency": "SAR",
"order_status": "RECEIVED",
"products": []
}
}Create Order
POST /api/v1/ordersRequest Body
{
"source": "erp",
"source_reference": "SO-2026-0042",
"source_transaction_id": "erp-txn-0042",
"destination": "branch_record_id",
"order_status": "RECEIVED",
"payment_status": "pending",
"fulfillment_status": "None",
"fulfillment_method": "delivery",
"payment_method": "cash",
"customer_name": "Sarah Smith",
"customer_email": "sarah@example.com",
"customer_phone": "+966509876543",
"skus": ["SKU-1"],
"products": [
{ "product_id": "prd_001", "sku_id": "SKU-1", "name": "Product One", "quantity": 2, "price": 29.99 }
],
"total_amount": 59.98,
"vat_amount": 9.0,
"discounts_amount": 0,
"currency": "SAR"
}Validation
| Field | Rule |
|---|---|
order_status | required (any non-blank value) |
payment_status | one of pending, processing, completed, failed, refunded |
fulfillment_status | required (any non-blank value) |
fulfillment_method | one of delivery, pickup, shipping |
payment_method | one of credit_card, debit_card, cash, bank_transfer, wallet |
currency | three letters |
skus | at least one |
products[] | each needs product_id and sku_id; price ≥ 0 |
total_amount, vat_amount, discounts_amount | ≥ 0 |
A repeated source_transaction_id is 409 Duplicate source transaction ID. Send X-Async: true to queue the write and poll GET /api/v1/jobs/{id}.
Response (201 Created)
{
"success": true,
"message": "Order created successfully",
"timestamp": "2026-04-21T10:30:00Z",
"data": {
"id": "r1234567890abcdef",
"order_number": "ORD-2026-001"
}
}Update Order
PUT /api/v1/orders/{id}Full replacement update. Include all fields you want to keep.
Update Order Status
Partial update for status fields only.
PATCH /api/v1/orders/{id}/statusRequest Body
{
"order_status": "DELIVERED",
"payment_status": "completed",
"fulfillment_status": "Full",
"notes": "Handed to the customer"
}All fields are optional — include only the statuses you want to change. For an order a vendor owns (Salla, Shopify, Zid, Trendyol, …) an order_status change is forwarded to the vendor first, and the response names it in forwarded_to.
Example
curl -X PATCH "https://linkit.works/api/v1/orders/r1234567890abcdef/status" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json" \
-d '{"order_status": "DELIVERED"}'Response
{
"success": true,
"message": "Order status updated successfully",
"timestamp": "2026-09-29T05:12:44Z",
"data": {
"id": "r1234567890abcdef",
"updated": { "order_status": "DELIVERED", "timestamp": "2026-09-29T05:12:44Z" }
}
}Bulk Operations
Bulk Create
POST /api/v1/orders/bulkCanonical request body is a named envelope. Max 100 per request. A top-level array is still accepted for older clients.
{
"mode": "create",
"orders": [
{
"source": "import",
"customer_name": "John Doe",
"total_amount": 59.98,
"currency": "SAR"
}
]
}Bulk Status Update
PATCH /api/v1/orders/bulk/status{
"updates": [
{ "id": "order_001", "order_status": "DELIVERED", "payment_status": "completed" },
{ "id": "order_002", "order_status": "CANCELLED" }
]
}Bulk Delete
DELETE /api/v1/orders/bulk{
"order_ids": ["order_001", "order_002", "order_003"]
}A top-level string array is still accepted.
Response (all bulk operations)
{
"success": true,
"data": {
"succeeded": 98,
"failed": 2,
"errors": {
"order_050": "Order not found",
"order_075": "Invalid status transition"
}
},
"timestamp": "2024-01-15T10:30:00Z"
}Error Responses
404 Not Found
{
"code": 404,
"error": "Order not found",
"details": { "id": "nonexistent" }
}422 Validation Error
{
"code": 422,
"error": "Validation failed",
"details": { "products": "At least one product is required" }
}Related
Order changes
Follow every change with a cursor — built for polling once a second.
Webhooks
Have order events pushed to you, signed.
Orders dashboard
Admin KPIs, heatmap, and the 5,000-row export. Sibling path — not /orders/dashboard.
Products
Product catalog for order line items.
Customers
Customer profiles linked to orders.