Linkit

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.

FieldTypeDescription
idstringOrder record id
organization_idstringTenant id
source_referencestringHuman or upstream reference
source_transaction_idstringIdempotency / upstream transaction key
source_timestampstringProvider timestamp (RFC3339), when known
destination_idstringBranch / store id in Linkit
destination_referencestringExternal branch or vendor reference
order_statusstringWorkflow status
fulfillment_statusstringFulfillment pipeline
payment_statusstringPayment pipeline
fulfillment_methodstringe.g. delivery, pickup, shipping
payment_methodstringTender / channel
currencystringISO 4217
total_amountnumberGrand total
discounts_amountnumberDiscounts
vat_amountnumberVAT
customer_name / customer_phone / customer_emailstringBuyer
receiver_name / receiver_phonestringRecipient when different
skusstring[]Sku codes when normalized
productsarrayLine items (normalized JSON)
shipping_addressobjectStructured address when present
order_codestringDisplay code
order_typestringOrder classification
transport_typestringLogistics / handoff hint
commentstringNotes
promised_forstringScheduled / promise time (RFC3339)
is_preorderbooleanPreorder flag
delivery_fee / service_fee / subtotalnumberFee breakdown
store_namestringResolved store label
dispatch_routingobjectDispatch metadata when present
shipping_fulfillmentobjectCarrier / fulfillment metadata when present
created_at / updated_atstringLinkit 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:

Sourceorder_statuspayment_statusfulfillment_status
Every connector (HungerStation, Jahez, Salla, Trendyol, …)RECEIVED, READY_FOR_PICKUP, DISPATCHED, DELIVERED, CANCELLEDpending, paid, refunded, failed, cancelledFull, Partial, None
Payment orders (/api/v1/payments/orders)pending, confirmedpending, completed—
POST /api/v1/orderswhatever you send (non-blank)pending, processing, completed, failed, refundedwhatever 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/orders

Every 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

ParameterTypeDefaultDescription
pageinteger1Page number (an invalid value falls back to 1)
limitinteger50Items per page, 1–100 (an invalid value falls back to 50)
statusstring-Filter by stored order_status (exact match, e.g. DELIVERED)
payment_statusstring-Filter by stored payment status
fulfillment_statusstring-Filter by stored fulfillment status
sourcestring-Filter by orders.source — for connector orders this is the install id, not the platform name
customer_emailstring-Exact customer email
currencystring-Three-letter code
min_amount / max_amountnumber-Bounds on total_amount
searchstring-Matches customer name, email, phone, receiver name, order id and source_transaction_id
fromstring-Lower bound on created (RFC 3339), e.g. 2026-04-21T00:00:00Z
tostring-Upper bound on created (RFC 3339)
sortstring-createdcreated, total_amount, customer_name, each optionally prefixed with -
formatstring-canonical returns canonical orders instead of the envelope below
includestring-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/orders

Request 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

FieldRule
order_statusrequired (any non-blank value)
payment_statusone of pending, processing, completed, failed, refunded
fulfillment_statusrequired (any non-blank value)
fulfillment_methodone of delivery, pickup, shipping
payment_methodone of credit_card, debit_card, cash, bank_transfer, wallet
currencythree letters
skusat 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}/status

Request 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/bulk

Canonical 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" }
}