Drop-ship

Drop-ship is the fulfillment pattern where the vendor ships goods directly to the customer; the warehouse never touches them. It’s table-stakes for marketplace platforms, 3PL operations, and any commerce surface where vendor-direct fulfillment is a margin strategy.

Per WMS ADR-0031, drop-ship is a multi-phase rollout: schema commitments ship in v1; Rule-driven PO generation activates in v1.4 with flow-service; full operator UX + drop-ship returns activate in v1.5+. The ingest API surface accepts the schema from v1 launch so upstreams can register drop-ship documents and FG.AI can store them without behavior loss when the runtime catches up.

The four variants

Variant

Description

Warehouse touches goods?

Inventory impact

Pure drop-ship

Vendor ships directly to customer.

No.

Zero.

Cross-dock drop-ship

Vendor ships to warehouse; warehouse immediately ships to customer (skip putaway).

Briefly (minutes/hours).

Transient RECEIVE → SHIP movements.

Hybrid SO

One SO has some lines drop-shipped + others shipped from stock.

Mixed per line.

Per-line.

Drop-ship returns

Customer returns a drop-shipped item; routes to vendor or warehouse.

Maybe.

Maybe.

These are not separate features — they’re configurations of the same mechanism: a Pull Rule generates a PO with ship_to_destination_frn = frn:wms:.../customer/{customer_id}, and vendor-reported events drive the SO line + PO line states without inventory writes.

Cross-dock drop-ship is actually a cross-dock Route — not real drop-ship from WMS’s perspective (the goods do pass through the warehouse). The cross-dock pattern uses a Route per WMS ADR-0029 §10, not the drop-ship mechanism.

v1 schema commitments

purchase_order_line (in procurement-service)

Column

Type

Default

Purpose

ship_to_destination_frn

FRN URN

frn:wms:.../warehouse-input/{warehouse_id}

Where the vendor ships the goods. Defaults to warehouse Input bin; overridden to frn:wms:.../customer/{customer_id} when the drop-ship Pull rule generates the PO.

linked_so_line_frn

FRN URN

NULL

Populated when the Procurement engine generates the PO from a specific SO line; enables cross-service traceability.

drop_ship_address

JSONB

NULL

Customer ship-to address copied from SO at PO generation time (immutable post-PO-approved). Includes name, address, contact phone, delivery instructions, signature required, etc.

fulfillment_mode

enum

from_stock

One of: from_stock (default — warehouse putaway), drop_ship_pure (vendor → customer), drop_ship_cross_dock (vendor → warehouse → customer same day).

sales_order_line (in fulfillment-service)

Column

Type

Default

Purpose

fulfillment_mode

enum

from_stock

Mirrors PO line — one of: from_stock (default — warehouse pick), drop_ship, mto, cross_dock. The Rule engine reads this when deciding which Route to apply.

linked_po_line_frn

FRN URN

NULL

Populated when the Procurement engine generates a drop-ship PO from this SO line; closes the round-trip linkage.

vendor_tracking_number

TEXT

NULL

Vendor-reported tracking number (populated from EDI 856 ASN or vendor portal callback); surfaces in customer-facing tracking.

Total v1 schema additions: 7 columns + 2 enums across two tables. Cheap insurance in v1; costly to add later on growing tables.

v1 behavior — schema-only

In v1 (Phases 1–7), the columns exist and are stored, but no v1 code path generates or routes a drop-ship document automatically. A v1 tenant who needs hand-coordinated drop-ship can:

  1. Create the SO with one or more lines tagged fulfillment_mode = drop_ship.

  2. Create a matching PO with ship_to_destination_frn set to the customer FRN and linked_so_line_frn set to the SO line FRN.

  3. Mark the SO line vendor_tracking_number when the vendor reports shipment.

  4. Close the SO line manually when delivery is confirmed (out of band).

This works but is operationally rough. Most v1 tenants leave drop-ship dormant and ship it via the upstream’s existing mechanism, exposing only the final state to FG.AI.

v1.4 — Rule-driven generation

In v1.4, flow-service ships a Procurement Pull Rule that observes SO lines tagged fulfillment_mode = drop_ship and automatically generates a matching PO with the right ship_to_destination_frn. From v1.4 forward, the upstream only needs to send the SO; FG.AI handles the rest.

The Rule reads vendor preference (Product.preferred_vendor), vendor lead time, customer address, and credit/risk flags. It is configurable per consignor (some consignors may opt out of automatic drop-ship; some may want approval gating).

v1.1 — EDI 856 / 855 are drop-ship-aware

Per WMS ADR-0021, v1.1 ships EDI 856 (Advance Ship Notice) inbound and EDI 855 (PO Acknowledgement) inbound. Both are essential for drop-ship: 856 carries the vendor tracking number that flows to sales_order_line.vendor_tracking_number; 855 confirms the PO acceptance status. v1.1 callers of the ingest API can populate these fields manually if they don’t yet wire EDI.

v1.5+ — full UX + drop-ship returns

The full drop-ship operator experience (visibility dashboard, exception management, vendor performance reporting) and drop-ship returns (customer returns a drop-shipped item; route to vendor or to a designated return-handling warehouse) ship in v1.5+. v1.5 returns flow is documented at WMS ADR-0030.

Examples

Pure drop-ship (v1.4 Rule-driven)

1. Upstream creates SO with one line:
   POST /documents/sales-orders
   { ..., "lines": [{ "sku_ref": "ACME-WIDGET", "qty": 1, "fulfillment_mode": "drop_ship" }] }

2. v1.4 Rule observes the line, generates a PO:
   PO line: { ..., "fulfillment_mode": "drop_ship_pure",
              "ship_to_destination_frn": "frn:wms:.../customer/cust-99",
              "linked_so_line_frn": "frn:wms:.../so-2026-00100/lines/1",
              "drop_ship_address": { ... } }

3. Vendor ships and reports tracking via EDI 856 (v1.1) or vendor portal callback:
   PATCH /sales-orders/SO-2026-00100/lines/1
   { "vendor_tracking_number": "1Z999AA1012345678" }

4. SO line closes when delivery is confirmed (vendor callback or scheduled rule).

Cross-dock drop-ship (v1.4)

1. Upstream creates SO with line: fulfillment_mode = cross_dock
2. v1.4 Rule generates PO with: fulfillment_mode = drop_ship_cross_dock,
   ship_to_destination_frn = the warehouse Input bin (not customer)
3. Goods arrive at warehouse Receiver, are not putaway, are immediately picked into a Shipper
4. Standard outbound flow ships to customer

The cross-dock case touches inventory transiently — receivers and shippers are real, lot/serial scans happen, the goods just don’t stay long enough to be putaway.

Anti-patterns

Sending a SO line with fulfillment_mode = drop_ship without a vendor identified. v1.4 needs Product.preferred_vendor set; v1 lets you set the field at SO time. Always populate.

Setting ship_to_destination_frn to a customer for a non-drop-ship PO. Quarantined as FULFILLMENT_MODE_INCONSISTENT.

Mixing drop-ship and from-stock on the same SO without per-line modes. Use per-line fulfillment_mode. The SO-level fulfillment_mode field is informational; the per-line value is authoritative.

Expecting v1 to generate drop-ship POs automatically. v1 stores schema only. v1.4 generates. Plan accordingly.