Orders — 受注ルーティング
任意のカートシステム(Shopify / BASE / 自社 EC 等)から受注と 出荷元(fulfillment source)ロケーションID を送ると、その出荷元に紐づく 在庫ロケーション(member)内だけ で引き当て先を判定し、拠点ごとに分割した canonical 出荷指示 を生成します。外部 fulfillment(WMS / 3PL)への push と同期レスポンスでの返却を同時に行います。Shopify orders webhook に依存しない cart-agnostic な汎用エンドポイントです。
出荷元 (fulfillment source) = 実際に出荷する拠点(例: MFCセンター東京)。在庫ロケーション (inventory location) = 在庫を持つ倉庫・店舗。1つの出荷元に複数の在庫ロケーションが紐づき(1出荷元 : N在庫)、出荷元の販売可能在庫はメンバー在庫の合算です。紐付けは
sot.lm_fulfillment_source_membersで管理します。
Base URL
https://api.lmile.io· 認証x-ingest-secretヘッダー(詳細) ·shopはリクエストボディに含めます(省略するとキーのアカウント)
エンドポイント
POST
/api/routing/orders
受注を受け取り出荷元を判定 → 出荷指示を生成・dispatch
POST
/api/routing/orders/shipped
取込元で引き渡しが終わっている注文(店頭販売など)を、その拠点から出荷済みで登録
入力フィールドは camelCase(
sourceSystem/externalOrderRef/fulfillmentSourceLocationId/shipTo/idempotencyKey)です。ingest 系の snake_case とは異なる点に注意してください。
POST /api/routing/orders
受注 1 件を受け取り、明細を unit(数量 1 個)単位で拠点へ配分し、出荷元ごとにまとめた出荷指示を返します。
リクエスト
POST https://api.lmile.io/api/routing/orders
x-ingest-secret: {INGEST_SECRET}
Content-Type: application/json{
"shop": "demo-store.myshopify.com",
"sourceSystem": "shopify",
"externalOrderRef": "1001",
"fulfillmentSourceLocationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel": "online_store",
"idempotencyKey": "shopify:1001",
"tag": "express",
"shipTo": {
"name": "山田 太郎",
"company": null,
"phone": "+819012345678",
"email": "taro@example.com",
"country": "JP",
"postalCode": "150-0001",
"prefecture": "東京都",
"city": "渋谷区",
"address1": "道玄坂1-2-3",
"address2": "○○ビル 4F"
},
"lines": [
{ "barcode": "1234567890123", "quantity": 2 },
{ "barcode": "1234567890456", "quantity": 1, "properties": { "刻印": "T.Y", "ギフト包装": "あり" } }
]
}ボディパラメータ
shop
string
店舗ドメイン(省略するとキーのアカウント)
sourceSystem
string
✓
カートの種別(shopify / base / self_ec 等、任意の識別子)。注文 identity・冪等キーの一部
externalOrderRef
string
✓
カート側の注文番号。注文 identity の一部
orderName
string
カート側の表示用注文番号(例 BJP999711)。倉庫間移動の内容物リスト(出荷ID配載 = W+数値部)・入荷予定 order_no の元値
referenceUrl
string (url)
カート側の注文参照 URL(例 Shopify admin の注文ページ https://admin.shopify.com/store/{handle}/orders/{id})。管理 UI が注文番号からカート管理画面へ遷移するリンクに使う。http(s) のみ
fulfillmentSourceLocationId
string (uuid)
✓
出荷元 location の id。この出荷元に紐づく在庫ロケーション内だけで引き当てる
inventoryLocationId
string (uuid)
引き当て先 在庫ロケーションの明示指定(任意)。指定時はこの location のみに引き当て(他メンバーへは振らない)。出荷元にマッピングされていなければ 422
suppressCustomerMail
boolean
true にすると、この注文では購入者にお届け状況メールを送りません(全段階とキャンセルのお知らせ)。一度指定すると取り消せません。省略時は店舗の通知設定どおり
suppressStorePrint
boolean
true にすると、この振り分けでは引き当て先の店舗で商品ラベル(統合QR)を自動印刷しません。引き当ての通知(Routing Allocation Webhook)は通常どおり送ります。省略時は印刷します
lines
array
✓
受注明細(1〜1,000 件)
channel
string
販売チャネル(channel_code または channel_id の UUID)。未解決でも在庫・拠点優先度で続行
shipTo
object
配送先(prefecture を region 判定に使用)
idempotencyKey
string
冪等キー。省略時は {sourceSystem}:{externalOrderRef} を自動採用
desiredDeliveryDate
string | null
配達希望日(ISO YYYY-MM-DD)。カート側が Shopify メタフィールド custom.pickup_date から取得。ラベル生成時に Ship&Co setup.date(配達指定日)へ載って佐川送り状へ印字。指定なしは未指定/null。後から手で設定する場合は Shipment Delivery
desiredDeliveryTime
string | null
配達希望時間帯(元表記。例 "午前中" / "12:00-14:00")。custom.pickup_time 由来。ラベル生成時に佐川コード(before-noon / 12-14 等)へ変換し setup.time へ載せる。佐川が認識しない表記は時間指定なし扱い
shipTo オブジェクト
Shopify MailingAddress / ship&co 準拠。全フィールド任意。出荷指示・WMS ディスパッチのテンプレート変数として使えます。
name
string
受取人氏名(ship&co full_name / Shopify name)
company
string
会社名
phone
string
電話番号(E.164 推奨)
email
string
メールアドレス
country
string
国コード(ISO-3166-1 alpha-2、例 JP)
postalCode
string
郵便番号(zip)
prefecture
string
都道府県(→ region に解決し地域一致スコアに使用。日本語都道府県名)
city
string
市区町村
address1
string
番地・町名
address2
string
建物名・部屋番号
lines[] オブジェクト
barcode
string
✓
商品識別子(sot.products との結合キー)
quantity
number
✓
数量(整数 1〜10,000)。unit 単位で拠点へ配分
properties
object
明細単位の任意キー/値(刻印テキスト・名入れ・ギフト指定等。Shopify line item property 相当)。最大 20 キー、キーは 1〜100 文字・値は 500 文字以内の文字列。省略 / null / 空 object は「なし」扱い。同一 barcode でも properties が異なる明細は別行のまま出荷指示・ピッキングリスト・dispatch payload へ透過されます
レスポンス
ok
通常 true。外部 dispatch が failed のときのみ false(HTTP は 200)
routingOrderId
routing order ヘッダの id(sot.lm_routing_orders.id)
status
received / routed / dispatched / failed / no_stock
shippingInstruction
拠点別に分割した canonical 出荷指示(下記)
dispatches
引き当て先ロケーションごとの送信結果配列(各 locationId / status: sent/failed/skipped / httpStatus / attempts / error)。送信先は Dispatch Config で登録
idempotent
既に dispatched 済の注文を再 POST した場合のみ true(再ルーティングせず既存結果を返却)
customerMailSuppressed / storePrintSuppressed
suppressCustomerMail / suppressStorePrint を受け付けたか。送った指定が false で返ってきたら、止まっていません
shippingInstruction
shipments[]
出荷元拠点ごとの出荷単位。fromLocationId / fromLocationLabel と lines[](barcode / quantity / properties。同一 barcode でも properties が異なれば別行。なしは null)
unroutableLines[]
引き当て不能だった分。barcode / quantity / reason(no_stock_anywhere 等)/ properties
serviceLines[]
非在庫サービス品(刻印サービス等、sot.products.is_non_inventory = true)の明細。barcode / quantity / properties。在庫引き当ての対象外(unroutableLines には含まれない)
decidedAt
判定時刻(ISO 8601, UTC)
ルーティング判定ロジック
各明細を unit 単位に展開し、指定された出荷元のメンバー在庫ロケーションを候補に順位付けして、在庫の続く限り上位拠点から greedy に配分します。
候補拠点: 指定された出荷元に紐づく 有効な在庫ロケーション(member)のみ(
sot.lm_fulfillment_source_membersのis_active = true)。出荷元の外の拠点やec_fulfillableフラグは判定に使いません(出荷元が EC 出荷の主体、member は在庫源)。在庫除外: 当該 barcode の
routable = available_qty + committed_qtyが 0 以下、または在庫レコード無しの member は除外(out_of_stock)。在庫の無い拠点には引き当てません。committed_qtyの送り方は Inventory Levels を参照。非在庫サービス品の除外:
sot.products.is_non_inventory = trueの商品(刻印サービス等、物理在庫を持たないサービス/カスタム明細)は在庫引き当ての対象外です。該当 unit はunroutableLinesではなくserviceLinesに分類され、判定根拠にはreason: non_inventory_serviceが記録されます(フラグの設定は ops の明示操作のみ。SKU や品名による自動判定はしません)。SKU 拠点オーバーライド(
sot.lm_sku_location_overrides):force_only— その拠点のみを候補にするavoid— その拠点を除外するforce_first— その拠点を常に最優先で引き当てる
引き当て順: 在庫のある候補を次の順で並べます — ①
force_first指定拠点 ② 出荷元自身の在庫(自己在庫を使い切ってから店舗メンバーへ)③ 販売可能在庫(available_qty)の多い順 ④ 配送先 region と拠点 region の一致 ⑤ member のpriorityRank昇順(未設定は最後)。committed_qtyは順位には使わず、引き当て可否(routable > 0)と配分数の上限にのみ使います。スコア内訳(拠点優先度・地域一致・在庫量スコア等)は判定根拠として保存されますが、順位の決定には使いません。配分: 順位の上位から数量を unit 単位で greedy 配分。在庫が尽きて余った unit は
unroutableLines(no_stock_anywhere)になります。明細のグルーピング: 同一
barcodeの複数明細(properties違い等)は合算して 1 回で引き当てます(別々に引き当てると在庫を二重参照するため)。引き当て後、unit(lineInstanceNo= 注文内 barcode 単位の連番)へ元明細の順にpropertiesを配り戻し、出荷指示・ピッキングリストではbarcode×properties単位で行を分けて集計します。引き当て先の明示指定:
inventoryLocationIdを指定すると候補をその location のみに限定します(出荷元の他メンバーへは振らない)。指定 location が出荷元にマッピングされていなければ422 location_not_member_of_source。在庫不足分はunroutableLines。
出荷後に在庫が実際には無かった(売越し)場合は、
/api/routing/oversellで該当結果に売越しフラグを立て、/api/routing/reallocateで同一出荷元の別メンバーへ再引き当てできます(Oversell / Reallocate)。
判定の根拠(拠点別スコア内訳・除外理由・採用理由)は sot.lm_routing_decisions / sot.lm_routing_candidates に監査ログとして保存されます。
挙動・冪等性
入口冪等:
(shop, sourceSystem, externalOrderRef)で routing order 1 行に収束します。status = dispatchedの注文を再 POST すると、再ルーティングせず既存の出荷指示をidempotent: trueで返します。再ルーティング: まだ dispatch されていない既存注文の再 POST は、前回の decision を破棄して再計算します。
出口冪等: 出荷指示は
(shop, idempotencyKey)で upsert され、外部への二重送信を防ぎます。外部 dispatch(per-location): 引き当て先の在庫ロケーションごとに登録された WMS 設定(Dispatch Config)でテンプレート描画して送信します(5xx は指数バックオフで最大 2 回再試行)。設定の無いロケーションは skip。結果は
dispatches[]で返し、sot.lm_location_dispatch_logに記録します(ルーティング結果は常に保存・返却)。在庫無し: 引き当てられた unit が 1 つも無ければ
status = no_stock、dispatch は skip(非在庫サービス品のみの注文も引き当て対象 unit が無いためno_stockになります)。dispatch 失敗時: HTTP は
200のままok: false/status: failedを返します(ルーティングは成功・保存済、外部送信のみ失敗)。ルーティング完了直後の引き当て結果は Routing Allocation Webhook で外部へ通知されます(設定時のみ。引き当て不能明細・
no_stockもunallocatedイベントとして通知)。出荷元の確認待ち: 出荷元を引き当ての前に確認するアプリを登録したストアでは、送った
fulfillmentSourceLocationIdと別の出荷元で引き当てることがあります。確認が取れないときは引き当てずに HTTP202でstatus = received/pending: "source_decision"/routingOrderId: nullを返し、確認が取れた時点でサーバー側が自動で引き当てます。再送は不要です(再送しても二重には引き当たりません)。アプリを登録していないストアでは起きません。通知・印刷を止める: 誤出荷の再手配など、購入者に知らせずに引き当てたいときは
suppressCustomerMail: trueを付けます。店舗での商品ラベルの印刷も要らないときは、あわせてsuppressStorePrint: trueを付けます。印刷を止めた注文を後から印刷したいときは、コンソールの出荷詳細から再印刷できます。
POST /api/routing/orders/shipped
取込元で既に引き渡しが終わっている注文(店頭販売など)を、受注と その拠点から出荷済みの出荷 として登録します。引き当て・在庫・配送ラベル・購入者への通知は動きません。
リクエスト
ボディパラメータ
shop
string
✓
店舗ドメイン
sourceSystem
string
✓
取込元の識別子(例 smaregi)
externalOrderRef
string
✓
取込元の注文 ID(例 スマレジの取引 ID)。sourceSystem との組で 1 注文
orderName
string
人が読む注文番号(例 BJP1000001)
referenceUrl
string
取込元の注文ページ URL(http(s) のみ)
locationId
uuid
△
出荷した拠点(= 引き当て拠点 = 出荷元)。location とどちらか一方
location
object
△
取込元の識別子で拠点を指す { "identifier_type", "identifier_value" }(例 smaregi_store_id)。locationId とどちらか一方
shippedAt
string
✓
引き渡した日時(ISO 8601。オフセット付き可)
orderedAt
string
注文の日時(ISO 8601)。受注の作成日時になります。省略すると shippedAt
channel
string
販売チャネル(channel_code か UUID。例 store)
shipTo
object
宛先(任意。項目は /api/routing/orders と同じ)
lines[]
array
✓
明細(1〜1000 行)。barcode / quantity(1 以上)と、任意の title / variantTitle
idempotencyKey
string
省略時 {sourceSystem}:{externalOrderRef}
dryRun
boolean
true で下見: 拠点の解決と判定だけ行い、何も書きません。{ "ok": true, "dryRun": true, "decision": "create" | "exists" | "cancelled" | "leg_cancelled" | "order_has_units", "units": 作る単位の数, "skippedLines": [...] } を返します(exists のときは既にある出荷の shipmentId / status も)
レスポンス
routingOrderId
受注の ID
shipmentId
作られた(または既にあった)出荷の ID
idempotent
true = その拠点の出荷が既にあり、何も変更していない(このときは skippedLines を返しません)
skippedLines[]
単位を作らなかった明細。non_inventory_service = 現物の無い同梱品(商品マスターで非在庫かつ付帯サービス。刻印サービスなど)
挙動・冪等性
送ると、受注 1 件とその拠点からの出荷 1 件(明細は数量ぶんの単位)が 出荷済み で作られます。お届け状況は「発送済み」になります。受注の作成日時は
orderedAt(省略時shippedAt)、出荷の作成日時はshippedAtです(過去の注文を後から登録しても、一覧の「直近」には並びません)。channelが店舗のチャネル(チャネルの種別がstore。スマレジの取引など)なら、購入者がその場で受け取っているので、お届け状況は 配達完了(配達完了日時 =shippedAt)になります。それ以外のチャネルやchannel省略時は「発送済み」のままです。現物の無い同梱品(商品マスターで非在庫かつ付帯サービス。刻印サービスなど)の明細は単位を作らず
skippedLines[]で返します。紙袋のように現物のある非在庫品は単位になります(引き当てと同じ扱い)。引き当て・在庫の予約・棚・配送ラベル・出荷指示の送信・引き当て通知・出荷ステータスの通知(Fulfillment Status Webhook)・購入者へのメールはどれも動きません。拠点の販売可能在庫は変わりません(店頭の在庫は取込元が正)。
出荷元の設定(出荷元とそのメンバー)は見ません。指定した拠点がそのまま出荷元になります。
冪等: 同じ注文にその拠点から出る出荷が既にあれば、作らずに
idempotent: trueと実際のstatusを返します。そのまま再送してよいです。「同じ注文」はexternalOrderRefが同じもの、または{externalOrderRef}-…の形(拠点・刻印・別の荷物・海外再発送で分けた注文)を含みます。この受け口が作った出荷なら、途中で失敗して欠けた単位を埋め直します。他の経路の出荷(引き当て済み・出荷元変更後など)には触りません。同じ注文で別の拠点を送ると、その拠点の出荷が追加されます(複数の店舗から渡した注文)。ただし、その注文に別の拠点の生きた単位があるときは
409 order_has_unitsで作りません。同じ注文・同じ拠点に取消済みの出荷があるときは作り直しません(
409 leg_cancelled)。商品マスターに無い
barcodeも登録します(SKU は空のまま)。取消済みの注文には登録しません(
409 order_cancelled)。
エラー
エンドポイント固有:
400
バリデーション失敗(fulfillmentSourceLocationId 欠落・非 UUID 含む)
{ "ok": false, "error": "invalid_input", "details": [{ "path": "fulfillmentSourceLocationId", "message": "..." }] }
422
出荷元が shop 内に存在しない
{ "ok": false, "error_kind": "fulfillment_source_unresolved", "error": "fulfillment source location not found for shop" }
422
出荷元に有効メンバーが無い
{ "ok": false, "error_kind": "fulfillment_source_no_members", "error": "fulfillment source has no active inventory-location members" }
422
指定 inventoryLocationId が出荷元のメンバーでない
{ "ok": false, "error_kind": "location_not_member_of_source", "error": "specified inventory location is not mapped to the fulfillment source" }
400
/orders/shipped: locationId と location の両方、またはどちらも無い
{ "ok": false, "error": "invalid_input", "details": [{ "path": "locationId", "message": "..." }] }
422
/orders/shipped: 拠点が解決できない(locationId が shop に無い / 識別子が未登録)
{ "ok": false, "error_kind": "location_unresolved", "error": "no location for smaregi_store_id=35" }
422
/orders/shipped: 識別子に複数の拠点が登録されている
{ "ok": false, "error_kind": "location_ambiguous", "error": "multiple locations for smaregi_store_id=35" }
409
/orders/shipped: 注文が取消済み
{ "ok": false, "error_kind": "order_cancelled", "error": "routing order is cancelled; not registering shipped leg" }
409
/orders/shipped: 同じ注文・同じ拠点に取消済みの出荷がある
{ "ok": false, "error_kind": "leg_cancelled", "error": "a cancelled leg already exists for this order at this location; not recreating", "shipmentId": "..." }
409
/orders/shipped: 注文に別の拠点の生きた単位がある
{ "ok": false, "error_kind": "order_has_units", "error": "routing order already has active units at another location; not adding a shipped leg" }
引き当て不能の明細はエラーではなく、レスポンス shippingInstruction.unroutableLines[] に reason 付きで返ります(正常処理を止めません)。非在庫サービス品(is_non_inventory = true)の明細は unroutableLines ではなく serviceLines[] に分類されます。共通エラー(401 / 400 / 403 / 405 / 500 / 503)は Error Codes を参照。
データモデル
sot.lm_fulfillment_source_members— 出荷元 → 在庫ロケーション 紐付け(1出荷元 : N在庫。UNIQUEshop + inventory_location_id)sot.lm_routing_orders— routing-native の注文ヘッダ(入口冪等。UNIQUEshop + source_system + external_order_ref)。status:received/routed/dispatched/failed/no_stocksot.lm_routing_decisions— unit 単位の判定結果(routing_order_id/barcode/line_instance_no/line_properties(=lines[].properties。名入れ等は顧客 PII になり得るためagent_read非公開)、fulfillment_source_location_id= 指定出荷元、selected_location_id= 引き当て先在庫ロケーション、decision_status = applied。売越し時はoversold/superseded_by_decision_id)sot.lm_routing_candidates— 判定時の候補スコア snapshot(拠点別スコア内訳・除外理由・rank)sot.lm_shipping_instructions— 出荷指示 dispatch ログ(delivery_status:pending/sent/failed/skipped。UNIQUEshop + idempotency_key)sot.lm_fulfillment_shipments/sot.lm_fulfillment_units—/orders/shippedが直接作る出荷と単位(status = shipped・decision 無し・在庫中立マーカーshelf_released_at付き)。sot.location_identifiersでlocationの識別子を拠点に解決参照(read):
sot.locations/sot.lm_location_priorities/sot.lm_sku_location_overrides/sot.lm_region_mappings/sot.channels/sot.products/sot.inventory_levels
受注の 販売実績 SoT(
sot.order_line_master)とは分離した routing-native の identity(source_system+external_order_ref+shipTo)を持ちます。ルーティングは販売実績の取込とは独立して動作します。
Last updated
Was this helpful?