> For the complete documentation index, see [llms.txt](https://lmile.gitbook.io/lmile-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lmile.gitbook.io/lmile-docs/fulfillment-api/pickup.md).

# Carrier Pickup — 集荷依頼

配送ラベルを発行済みの出荷をまとめて、キャリアの\*\*集荷（オンコールピックアップ）\*\*を依頼します。対応キャリアは **UPS** です。集荷は「この拠点に、この日、この時間帯に、この個口数を取りに来てもらう」**1 回の訪問**なので、複数の出荷をまとめて 1 リクエストで依頼します。依頼が成功すると集荷受付番号（PRN）が返り、取消にも使えます。

> **Base URL** `https://api.lmile.io` · **認証** `x-ingest-secret` ヘッダー または operator JWT（`Authorization: Bearer`）（[詳細](/lmile-docs/getting-started/authentication.md)） · `shop` はリクエストボディに含めます（API キーで呼ぶ場合は省略できます）

> 出荷 1 件につき 1 回ずつ依頼すると、同じ日に受付番号が個数ぶん立ってしまいます（キャリアには「1 訪問で全部引き取る」としか伝わりません）。**その訪問で渡す出荷を 1 リクエストにまとめて**送ってください。

## エンドポイント

| Method | Path                         | 用途                        |
| ------ | ---------------------------- | ------------------------- |
| `POST` | `/api/routing/pickup`        | 選んだ出荷をまとめて 1 回の集荷として依頼する  |
| `POST` | `/api/routing/pickup/cancel` | 依頼済みの集荷を取り消し、対象の出荷を未依頼に戻す |

集荷先の住所・キャリアの認証情報・既定の時間帯は、**出荷元拠点ごとの設定**（[Dispatch Config](/lmile-docs/configuration/dispatch-config.md) の `action: "pickup"`）から読みます。設定が無い拠点に依頼すると、エラーではなく `requestable: false` と理由を返します。

***

## `POST` /api/routing/pickup

選んだ出荷を 1 回の集荷にまとめて依頼します。個口数と宛先国は**出荷そのものから決まる**ので送りません（渡すのは日時と総重量だけです）。

### リクエスト

```http
POST https://api.lmile.io/api/routing/pickup
x-ingest-secret: {INGEST_SECRET}
Content-Type: application/json
```

```json
{
  "shop": "demo-store.myshopify.com",
  "shipmentIds": [
    "11494bc4-f45f-4d0b-9d68-fd26c1a503ec",
    "3896ae59-2b71-4b0c-9f8e-1c0a2d5e7b41"
  ],
  "pickupDate": "2026-08-20",
  "readyTime": "1600",
  "closeTime": "1800",
  "totalWeightKg": 1.2
}
```

### ボディパラメータ

| パラメータ           | 型                |  必須 | 説明                                                                  |
| --------------- | ---------------- | :-: | ------------------------------------------------------------------- |
| `shop`          | string           |  ✓  | 店舗ドメイン（API キーで呼ぶ場合は省略できます）                                          |
| `shipmentIds`   | string\[] (uuid) |  ✓  | この訪問で渡す出荷（1〜100 件）。全件が同じ出荷元拠点・同じキャリアであること                           |
| `pickupDate`    | string           |  ✓  | 集荷日 `YYYY-MM-DD`                                                    |
| `readyTime`     | string           |     | 荷物の準備が終わる時刻 `HHmm`（24 時間表記・区切り無し）。省略すると拠点の既定値                       |
| `closeTime`     | string           |     | 集荷の締め時刻 `HHmm`。省略すると拠点の既定値。`readyTime` より後であること                     |
| `totalWeightKg` | number           |  ✓  | 引き渡す荷物の総重量（kg）                                                      |
| `pickupAddress` | object           |     | 集荷先住所の上書き。省略すると拠点の設定に登録された住所を使います。**この 1 回の依頼にだけ効きます**（設定は書き換わりません） |

#### `pickupAddress` オブジェクト

| パラメータ                                   | 型      |  必須 | 説明                                       |
| --------------------------------------- | ------ | :-: | ---------------------------------------- |
| `companyName` / `contactName` / `phone` | string |  ✓  | 集荷先の会社名・担当者名・電話番号                        |
| `addressLine`                           | string |  ✓  | 番地・建物。**1 本の文字列**で送ります                   |
| `city`                                  | string |  ✓  | 市区町村                                     |
| `stateProvince`                         | string |  ✓  | 都道府県・州を **ISO 3166-2**（例: 大阪 = `JP-27`）で |
| `postalCode`                            | string |  ✓  | 郵便番号（ハイフンは自動で除去します）                      |
| `countryCode`                           | string |  ✓  | 国コード（ISO 3166-1）                         |
| `residentialIndicator`                  | string |     | `Y` = 住宅 / `N` = オフィス（既定 `N`）            |

### レスポンス

```json
{
  "ok": true,
  "requestable": true,
  "pickupId": "9f2c1b7a-0d54-4b93-9a1e-6c7d8e5f0a12",
  "prn": "2980715C182",
  "pickupDate": "2026-08-20",
  "readyTime": "1600",
  "closeTime": "1800",
  "pieces": [
    { "destinationCountryCode": "US", "quantity": 2 },
    { "destinationCountryCode": "TW", "quantity": 1 }
  ],
  "totalWeightKg": 1.2,
  "shipmentIds": ["11494bc4-...", "3896ae59-..."]
}
```

| フィールド           | 説明                                                       |
| --------------- | -------------------------------------------------------- |
| `prn`           | キャリアの集荷受付番号。**取消に必要なので控えてください**                          |
| `pickupId`      | この依頼の識別子。取消はこちらを使います                                     |
| `pieces`        | 宛先国ごとの個口数。選んだ出荷の配送先から自動で組み立てた内訳です                        |
| `pickupAddress` | 実際に使われた集荷先住所（上書きした場合はその値）                                |
| `requestable`   | `false` のときは依頼していません（`reason` に理由）。この場合も HTTP は `200` です |

### 挙動・冪等性

* **依頼できるのは、配送ラベルが発行済みで、まだ出荷していない出荷だけ**です。取消済み・出荷済み・アーカイブ済み・ラベル未発行が含まれていると、**該当する出荷を全部** `422` の `shipments[]` で返します（1 件目で打ち切らないので、何を外せばよいかが一度で分かります）。
* **出荷元がばらけている選択は受け付けません**（`422`）。集荷は 1 拠点への 1 訪問なので、拠点ごとに分けて依頼してください。
* **一度依頼した出荷は、取り消すまで別の依頼に入れられません**（`409`）。既にどの依頼に入っているかを受付番号つきで返すので、そのまま画面に出せます。**これが二重手配の防止点です**。
* **同時に 2 か所から依頼しても、受付番号は 1 つしか立ちません**。キャリアへ問い合わせる前に対象の出荷を予約するので、あとから来たリクエストはキャリアに触れずに `409` で止まります。
* **キャリアへの依頼が失敗したときは、対象の出荷は未依頼のまま**です（予約は自動で解除されます）。原因を直してそのまま再送してください。
* **集荷先住所を上書きしたときも、設定に登録した住所と同じ検証を通ります**（`addressLine` は 1 本の文字列 / `stateProvince` は ISO 3166-2 / `postalCode` はハイフン除去）。項目が欠けていると既定値では埋めず、足りない項目を挙げて `422` を返します。
* 依頼の記録は各出荷の操作履歴にも残ります（受付番号・日時・個口数・総重量）。
* 集荷先住所が**設定と違う値だったときだけ**、その住所も操作履歴に残します。判定は `pickupAddress` を送ったかどうかではなく**値の比較**なので、画面に出ている住所をそのまま送り返しても「上書きした」記録にはなりません（郵便番号のハイフン等の表記揺れは揃えてから比べます）。

***

## `POST` /api/routing/pickup/cancel

依頼済みの集荷を取り消します。\*\*時間帯や対象を変えたいときは「取消 → 依頼し直し」\*\*で行ってください（依頼の書き換えはできません）。

### リクエスト

```http
POST https://api.lmile.io/api/routing/pickup/cancel
x-ingest-secret: {INGEST_SECRET}
Content-Type: application/json
```

```json
{
  "shop": "demo-store.myshopify.com",
  "pickupId": "9f2c1b7a-0d54-4b93-9a1e-6c7d8e5f0a12",
  "reason": "時間帯を変更するため"
}
```

| パラメータ      | 型             |  必須 | 説明                                                          |
| ---------- | ------------- | :-: | ----------------------------------------------------------- |
| `shop`     | string        |  ✓  | 店舗ドメイン（API キーで呼ぶ場合は省略できます）                                  |
| `pickupId` | string (uuid) |  ✓  | 取り消す依頼                                                      |
| `reason`   | string        |     | 取消理由（記録用・200 文字まで）                                          |
| `force`    | boolean       |     | 受付番号が記録されていない依頼を解除する場合のみ `true`。キャリア側に集荷が無いことを確認してから使ってください |

### レスポンス

```json
{
  "ok": true,
  "cancelledAtCarrier": true,
  "pickupId": "9f2c1b7a-...",
  "prn": "2980715C182",
  "releasedShipmentIds": ["11494bc4-...", "3896ae59-..."]
}
```

| フィールド                 | 説明                                                                 |
| --------------------- | ------------------------------------------------------------------ |
| `cancelledAtCarrier`  | `true` = キャリア側の集荷を取り消しました。`false` = 受付番号が立つ前の予約だったので、こちらの解除だけ行いました |
| `releasedShipmentIds` | 未依頼に戻した出荷。そのまま別の依頼に入れられます                                          |

### 挙動・冪等性

* **キャリア側の取消が成功してから、こちらの出荷を未依頼に戻します**。逆にすると、キャリアには集荷が残っているのに画面上は未依頼になり、同じ荷物にもう 1 回集荷を呼んでしまいます。
* キャリアの取消が失敗した場合は `502` を返し、**対象の出荷は依頼済みのまま**にします。原因を直して再送してください。
* 取消済みの依頼をもう一度取り消すと `409` を返します（黙って成功にしません）。
* **受付番号が記録されていない依頼は、既定では取り消せません**（`409` `pickup_prn_unknown`）。キャリアに集荷が残っているのにこちらだけ未依頼に戻すと、同じ荷物にもう 1 回集荷を呼ぶことになるためです。キャリア側に集荷が無いことを確認できた場合だけ `force: true` を付けて解除してください。

## エラー

エンドポイント固有:

| Status | 条件                                                          | レスポンス例                                                                                                                   |
| :----: | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|  `404` | `shipmentIds` に同一 shop で存在しない出荷がある                          | `{ "ok": false, "error_kind": "shipment_not_found", "missing": [...] }`                                                  |
|  `404` | `pickupId` が同一 shop に存在しない                                  | `{ "ok": false, "error_kind": "pickup_not_found" }`                                                                      |
|  `409` | 既に依頼済みの出荷が含まれている                                            | `{ "ok": false, "error_kind": "pickup_already_requested", "prn": "2980715C182", "pickupDate": "2026-08-20" }`            |
|  `409` | 取消済み / 失敗済みの依頼を取り消そうとした                                     | `{ "ok": false, "error_kind": "pickup_not_active", "status": "cancelled" }`                                              |
|  `422` | 集荷に載せられない出荷が含まれている                                          | `{ "ok": false, "error_kind": "shipment_not_pickupable", "shipments": [{ "id": "...", "reason": "label_not_issued" }] }` |
|  `422` | 出荷元がばらけている                                                  | `{ "ok": false, "error_kind": "pickup_source_mixed", "sourceLocationIds": [...] }`                                       |
|  `422` | UPS 以外の出荷が混ざっている                                            | `{ "ok": false, "error_kind": "pickup_carrier_mismatch", "shipments": [...] }`                                           |
|  `422` | 配送先の国が分からない出荷がある（個口の内訳を組めません）                               | `{ "ok": false, "error_kind": "pickup_destination_country_missing", "shipmentIds": [...] }`                              |
|  `422` | 拠点の集荷設定が不正 / 取消時に設定が見つからない                                  | `{ "ok": false, "error_kind": "pickup_config_invalid", "error": "pickupAddress missing: stateProvince" }`                |
|  `422` | 上書きした `pickupAddress` の項目が欠けている                             | `{ "ok": false, "error_kind": "pickup_address_invalid", "error": "pickupAddress missing: stateProvince, phone" }`        |
|  `409` | 受付番号が記録されていない依頼を取り消そうとした                                    | `{ "ok": false, "error_kind": "pickup_prn_unknown", "pickupId": "..." }`                                                 |
|  `502` | キャリアが依頼 / 取消を拒否した（キャリアの応答をそのまま載せます）                         | `{ "ok": false, "error_kind": "ups_pickup_failed", "error": "UPS HTTP 400 [9510119: Invalid service designation]" }`     |
|  `500` | キャリアは集荷を受け付けたが、こちらの記録に失敗した（**受付番号は `error` と `prn` に載ります**） | `{ "ok": false, "error_kind": "pickup_finalize_failed", "prn": "2980715C182" }`                                          |

`shipment_not_pickupable` の `reason` は `cancelled` / `already_shipped` / `archived` / `label_not_issued` のいずれかです。

共通エラー（`401` / `400` / `403` / `405` / `500` / `503`）は [Error Codes](/lmile-docs/reference/error-codes.md) を参照。

## データモデル

* `sot.lm_carrier_pickups` — 集荷依頼 1 回分のヘッダ。受付番号（`prn`）・集荷日・時間帯・宛先国ごとの個口内訳（`pieces`）・総重量・依頼者を保持します。`status` は `pending`（キャリアへ問い合わせる前の予約）→ `requested`（受付番号あり）/ `failed`、取消は `cancelled`。
* `sot.lm_fulfillment_shipments.pickup_id` — 出荷とその依頼の関連。**この列が非 NULL であることが「集荷依頼済み」の判定**です（取消・失敗で NULL に戻ります）。
* `public.lm_v_fulfillment_shipments.pickup_id` — 出荷作業一覧の read 用ビューにも同じ列を出しています。
* `sot.lm_location_dispatch_config`（`action = 'pickup'`, `adapter_type = 'ups_pickup'`）— 出荷元拠点ごとの集荷設定。キャリア認証情報は暗号化して保存し、集荷先住所・サービスコード・既定の時間帯を `payload_template` に持ちます。
* `sot.lm_shipment_memos` — 依頼・取消の操作履歴（実行者と受付番号）。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://lmile.gitbook.io/lmile-docs/fulfillment-api/pickup.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
