Inbound Slots & Purchase Orders

Inbound Slots & Purchase Orders Guide

This guide explains the slot-based inbound flow: book a delivery slot, get it confirmed by the fulfilment centre, then create the purchase order against the approved slot.

Overview

Unlike the legacy POST /inbound (asynchronous record processing), this flow:

  1. Books a delivery slot first — you request a date and time window
  2. Negotiates with the fulfilment centre — the FC confirms your slot, or proposes a different time that you can accept or counter
  3. Creates the purchase order synchronously against the approved slot — the PO exists in the warehouse system the moment the request returns
  4. Tracks the delivery end-to-end — schedule, arrival, unloading, discrepancy and partial-delivery state are all readable per PO
Request slot ──► pending_ops ──FC confirms──────────► confirmed ──► Create PO (slot consumed)
                     ▲          └─FC counters──► pending_customer
                     └───────you counter─────────────┘└──you accept──► confirmed

The Flow, Step by Step

Step 1: Request a slot

POST /inbound-slot
{
  "date": "2026-08-25",
  "window": "morning",
  "warehouse": "RHEINE01",
  "loadingType": "palletised",
  "numberOfSkus": "lt_10",
  "deliveryType": "container",
  "containerSize": "40ft",
  "palletCount": 12
}

Rules:

  • date must not be in the past. Mondays are not available, except at warehouses that accept Monday inbounds (WMS UK NDC, Devoko)
  • window sets the arrival time: morning = 09:00 UK, afternoon = 13:00 UK
  • containerSize is required for container deliveries

The response returns your slotReference; the slot starts in scheduleStatus: pending_ops (waiting on the warehouse).

Step 2: Poll until the warehouse responds

Warehouse approval is asynchronous. Poll the slot (a few times per hour is plenty):

GET /inbound-slot/{slotReference}
  • scheduleStatus: confirmed → done, go to Step 4
  • scheduleStatus: pending_customer → the FC proposed a different time, go to Step 3

You can also list all your slots with GET /inbound-slot, or only the ready-to-use ones with GET /inbound-slot?available=true.

Step 3: Accept or counter the FC's proposal

When pending_customer, the pending proposal with "proposedBy": "ops" in schedule.proposals is the warehouse's offer:

POST /inbound-slot/{slotReference}/respond
{ "action": "accept" }

or counter with a new time (ISO 8601 with offset; the slot returns to pending_ops):

{ "action": "counter", "proposedTime": "2026-08-27T09:00:00+01:00", "comment": "Truck only free Thursday" }

This can go back and forth as many rounds as needed. A 409 means the schedule changed concurrently — re-read the slot and respond again.

Step 4: Create the purchase order against the confirmed slot

POST /inbound-po
{
  "PO_REFERENCE": "BRAND-PO-2026-001",
  "Warehouse_Name": "RHEINE01",
  "slotReference": "SLOT-Brand-2026081815163644",
  "deliveryType": "container",
  "loadingType": "palletised",
  "palletCount": 12,
  "items": [
    { "SKU": "PROD-12345", "barcode": "4001234567890", "Quantity": 100 }
  ]
}

The PO is created immediately in the warehouse system with the slot's confirmed time as its delivery date, and the response returns the generated lw_po_number. The slot is claimed atomically — it can never be consumed twice — and is released again automatically if PO creation fails.

⚠️

Expected_Arrival_Date is deprecated on this endpoint: sending it without a slotReference returns 409. Delivery dates are agreed via slots.

Step 5: Track the delivery

GET /inbound-po/{poReference}

Use the lw_po_number from Step 4. The response includes the live PO status and line items (ordered vs delivered), your delivery details, the full schedule negotiation, and the warehouse's inbound report once processed (arrival/unloading times, checklist, discrepancies, partial-delivery state).

Code Example (Python)

import requests, time

BASE = "https://api.spreetaileu.com/api/api/v1"

def headers(token):
    return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}

# Step 1: request a slot
slot = requests.post(f"{BASE}/inbound-slot", headers=headers(token), json={
    "date": "2026-08-25", "window": "morning", "warehouse": "RHEINE01",
    "loadingType": "palletised", "numberOfSkus": "lt_10", "palletCount": 12,
}).json()
slot_ref = slot["slotReference"]

# Step 2: poll until confirmed (respond to counters as needed)
while True:
    detail = requests.get(f"{BASE}/inbound-slot/{slot_ref}", headers=headers(token)).json()["data"]
    status = detail["scheduleStatus"]
    if status == "confirmed":
        break
    if status == "pending_customer":
        # Step 3: accept the FC's proposal (or counter)
        requests.post(f"{BASE}/inbound-slot/{slot_ref}/respond",
                      headers=headers(token), json={"action": "accept"})
    time.sleep(600)

# Step 4: create the PO against the confirmed slot
po = requests.post(f"{BASE}/inbound-po", headers=headers(token), json={
    "PO_REFERENCE": "BRAND-PO-2026-001", "Warehouse_Name": "RHEINE01",
    "slotReference": slot_ref, "deliveryType": "truck", "loadingType": "palletised",
    "palletCount": 12,
    "items": [{"SKU": "PROD-12345", "barcode": "4001234567890", "Quantity": 100}],
}).json()
print("PO created:", po["data"]["lw_po_number"])

Important Notes

Slot lifecycle

  • A slot is single-use: once a PO consumes it, usedByPoReference is set and it cannot be reused or cancelled
  • Unused slots can be cancelled with DELETE /inbound-slot/{slotReference} (idempotent)
  • Approved-but-unused slots should be consumed before requesting new dates

Item resolution

Every item on POST /inbound-po must resolve to exactly one known product — matched by barcode first, then SKU. Unknown or ambiguous items reject the whole request (400), and the error lists the offending SKUs.

Failure handling

If PO creation fails after the slot was claimed, the slot is released automatically and the response includes "retryable": true with the reserved lw_po_number. Fix the cause (for example an unknown SKU) and retry.

Related Endpoints

  • POST /inbound — legacy asynchronous inbound flow (unchanged; no slot booking)
  • GET /inventory — check updated inventory levels after delivery

Did this page help you?