> For the complete documentation index, see [llms.txt](https://apidocs.nhanh.vn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://apidocs.nhanh.vn/v3/ship/create.md).

# Tạo đơn

* Tạo đơn hàng vận chuyển mới và lưu vào hệ thống.
* **Hỗ trợ:** Tạo đơn hàng đơn lẻ với thông tin người gửi, người nhận và kiện hàng.
* **Tùy chọn:** Nếu truyền `sendCarrier = 1`, hệ thống sẽ tự động gửi đơn sang hãng vận chuyển ngay sau khi lưu thành công.

## Request

* Xem [common request params](/v3/readme.md#request-params).
* Xem [Postman sample](/v3/ship/create.md).

```curl
curl --location 'https://ship.open.nhanh.vn/v3.0/shipment/create?businessId={{businessId}}&appId={{appId}}' \
--header 'Authorization: {{accessToken}}' \
--header 'Content-Type: application/json' \
--data '{
    "businessStoreId": 123,
    "appOrderId": "13213123",
    "sender": {
        "name": "Nguyễn Văn A",
        "mobile": "0901234567",
        "shippingLocation": {
            "locationVer": "v2",
            "provinceId": 1,
            "wardId": 100,
            "address": "123 Nguyễn Trãi, Thanh Xuân, Hà Nội",
            "longitude": 105.804567,
            "latitude": 21.001234
        }
    },
    "receiver": {
        "name": "Trần Thị B",
        "mobile": "0912345678",
        "shippingLocation": {
            "locationVer": "v2",
            "provinceId": 48,
            "wardId": 12345,
            "address": "456 Lê Lợi, Hải Châu, Đà Nẵng",
            "longitude": 108.212345,
            "latitude": 16.067890
        }
    },
    "products": [
        {
            "name": "Áo thun cotton",
            "quantity": 2,
            "price": 150000,
            "weight": 300
        }
    ],
    "weight": 1500,
    "packageDimensions": {
        "width": 30,
        "height": 20,
        "length": 40
    },
    "codAmount": 650000,
    "description": "Thời trang nam nữ",
    "carrier": {
        "id": 18,
        "serviceId": 100,
        "promoCode": "GIAM10"
    },
    "carrierExtraServices": {
        "allowTest": true,
        "declaredSetting": true,
        "declaredAmount": 500000
    },
    "shipFeeBy": "sender",
    "sendCarrier": 1
}'
```

### Body

| Key                  | Type                        | Description                                                                                                                           |
| -------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| businessStoreId      | int $$^{\color{red}\*}$$    | ID cửa hàng của doanh nghiệp trên app của bạn                                                                                         |
| appOrderId           | string $$^{\color{red}\*}$$ | ID đơn hàng trên App của bạn                                                                                                          |
| sender               | object $$^{\color{red}\*}$$ | Thông tin người gửi. Xem [Sender](#sender)                                                                                            |
| receiver             | object $$^{\color{red}\*}$$ | Thông tin người nhận. Xem [Receiver](#receiver)                                                                                       |
| products             | array                       | Danh sách sản phẩm trong đơn hàng. Xem [Products](#products)                                                                          |
| weight               | int $$^{\color{red}\*}$$    | Khối lượng thực tế của đơn hàng (gram). Xem [Quy tắc tính khối lượng](#quy-tắc-tính-khối-lượng)                                       |
| packageDimensions    | object                      | Kích thước kiện hàng (cm). Xem [Package Dimensions](#package-dimensions)                                                              |
| codAmount            | int                         | Số tiền thu hộ (COD), đơn vị VND. Mặc định: `0`                                                                                       |
| description          | string                      | Mô tả đơn hàng                                                                                                                        |
| carrier              | object $$^{\color{red}\*}$$ | Thông tin hãng vận chuyển. Xem [Carrier](#carrier)                                                                                    |
| carrierExtraServices | object                      | Các dịch vụ bổ sung. Xem [Carrier Extra Services](#carrier-extra-services)                                                            |
| shipFeeBy            | string                      | Người trả phí: `"sender"` (mặc định) hoặc `"receiver"`                                                                                |
| sendCarrier          | int                         | Tự động gửi đơn sang hãng vận chuyển: `1` = có, `0`/`null` = không (mặc định). Xem [Gửi đơn sang hãng](#gửi-đơn-sang-hãng-vận-chuyển) |

### Carrier

Thông tin hãng vận chuyển và phí. **Lấy từ response của API** [**Tính cước phí**](/v3/ship/rate.md).

* **Lưu ý**: Sẽ có 2 trường hợp chênh lệch giá khi Tính cước phí và khi Tạo đơn hàng với dịch vụ INSTANT
  * *Trường hợp 1*: Nếu Đối tác gọi API Tính cước phí và gọi API Tạo đơn hàng ngay sau đó thì sẽ không có chênh lệch giá giữa 2 lần gọi
  * *Trường hợp 2*: Nếu thời điểm Đối tác gọi API Tính cước phí và Tạo đơn cách nhau một khoảng thời gian thì tại thời điểm tạo đơn, giá sẽ khác so với thời điểm Tính cước phí. Sự chênh lệch này phụ thuộc vào các yếu tố như thời tiết xấu, giờ cao điểm, ngày lễ,...

| Key       | Type                     | Description                                                                                                      |
| --------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| id        | int $$^{\color{red}\*}$$ | ID hãng vận chuyển. Xem [Supported Carriers](/v3/ship/list.md)                                                   |
| serviceId | int                      | ID dịch vụ vận chuyển. **Lấy từ field `serviceId` trong response của API** [**Tính cước phí**](/v3/ship/rate.md) |
| promoCode | string                   | Mã khuyến mãi/voucher                                                                                            |

### Lấy giá từ Rate

Các params về phí vận chuyển **được lấy từ response của API** [**Tính cước phí**](/v3/ship/rate.md) ( `POST /v3.0/shipment/rate`).

**Luồng thực hiện:**

```
1. Gọi POST /v3.0/shipment/rate
   ↓
2. Response trả về danh sách dịch vụ:
   [
     {
       "carrierId": 18,
       "serviceId": 100,
       "promoCode": "GIAM10"
     }
   ]
   ↓
3. User chọn 1 dịch vụ
   ↓
4. Gọi POST /v3.0/shipment/create với các giá trị đã lấy
```

> **Quan trọng:** Nên gọi API [Tính cước phí](/v3/ship/rate.md) trước để lấy `carrier.serviceId`.

### Declared Fee

| Giá trị        | Ý nghĩa                                                         |
| -------------- | --------------------------------------------------------------- |
| `0` (mặc định) | Không khai giá hàng hóa                                         |
| `> 0`          | Số tiền khai giá (VD: `500000` = khai hàng trị giá 500,000 VND) |

**Khi nào dùng:**

* Cần bảo hiểm hàng hóa cho kiện có giá trị cao
* Hãng vận chuyển yêu cầu khai giá cho hàng hóa đặc biệt
* Khi bật `carrierExtraServices.declaredSetting = true`

### Sender

| Key              | Type                        | Description                                                   |
| ---------------- | --------------------------- | ------------------------------------------------------------- |
| name             | string $$^{\color{red}\*}$$ | Tên người gửi                                                 |
| mobile           | string $$^{\color{red}\*}$$ | Số điện thoại người gửi                                       |
| shippingLocation | object                      | Địa chỉ lấy hàng. Xem [Shipping Location](#shipping-location) |

### Receiver

| Key              | Type                        | Description                                                    |
| ---------------- | --------------------------- | -------------------------------------------------------------- |
| name             | string $$^{\color{red}\*}$$ | Tên người nhận                                                 |
| mobile           | string $$^{\color{red}\*}$$ | Số điện thoại người nhận                                       |
| shippingLocation | object                      | Địa chỉ giao hàng. Xem [Shipping Location](#shipping-location) |

### Shipping Location

Đối tượng mô tả địa điểm (dùng cho cả sender và receiver).

> * `locationVer` của **sender** và **receiver** phải giống nhau (cùng là `"v1"` hoặc cùng là `"v2"`).
> * Nếu dùng `locationVer = "v1"`: bắt buộc truyền đủ `provinceId`, `districtId`, `wardId`.
> * Nếu dùng `locationVer = "v2"`: chỉ cần `provinceId` và `wardId` (không bắt buộc `districtId`).
> * Nếu không truyền `locationVer`: mặc định là `"v2"`.
> * longitude, latitude bắt buộc khi dùng dịch vụ Instant

| Key         | Type                        | Description                                                                                                                            |
| ----------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| locationVer | string                      | Phiên bản dữ liệu địa chỉ: `"v1"` (3 cấp: provinceId + districtId + wardId) hoặc `"v2"` (2 cấp: provinceId + wardId). Mặc định: `"v2"` |
| provinceId  | int $$^{\color{red}\*}$$    | ID tỉnh/thành phố                                                                                                                      |
| districtId  | int $$^{\color{red}\*}$$    | ID quận/huyện                                                                                                                          |
| wardId      | int $$^{\color{red}\*}$$    | ID phường/xã                                                                                                                           |
| address     | string $$^{\color{red}\*}$$ | Địa chỉ chi tiết (số nhà, tên đường)                                                                                                   |
| longitude   | number                      | Kinh độ (dùng thay thế cho provinceId/districtId/wardId) (                                                                             |
| latitude    | number                      | Vĩ độ (dùng thay thế cho provinceId/districtId/wardId)                                                                                 |

### Products

* Cấu trúc `products` được pass-through trực tiếp đến từng hãng vận chuyển. Các field con có thể khác nhau tùy hãng.

| Key      | Type   | Description                  |
| -------- | ------ | ---------------------------- |
| name     | string | Tên sản phẩm                 |
| quantity | int    | Số lượng. Mặc định: `1`      |
| price    | number | Đơn giá sản phẩm (VND)       |
| weight   | int    | Khối lượng 1 sản phẩm (gram) |

### Package Dimensions

| Key    | Type | Description               |
| ------ | ---- | ------------------------- |
| width  | int  | Chiều rộng kiện hàng (cm) |
| height | int  | Chiều cao kiện hàng (cm)  |
| length | int  | Chiều dài kiện hàng (cm)  |

### Quy tắc tính khối lượng

Xem [Quy tắc tính khối lượng quy đổi](/v3/ship/rate.md#package-dimensions) trong tài liệu Rate API.

### Carrier Extra Services

| Key             | Type   | Description                                                                         |
| --------------- | ------ | ----------------------------------------------------------------------------------- |
| allowTest       | bool   | Cho phép người nhận thử hàng trước khi thanh toán. Mặc định: `false`                |
| declaredSetting | bool   | Bật khai giá hàng hóa. Mặc định: `false`                                            |
| declaredAmount  | int    | Số tiền khai giá (VND). Mặc định: `0`. Chỉ có hiệu lực khi `declaredSetting = true` |
| declaredService | object | Cấu hình chi tiết dịch vụ khai giá (tùy hãng). Pass-through trực tiếp               |

### Gửi đơn sang hãng vận chuyển

Khi truyền `sendCarrier = 1`:

1. Hệ thống lưu đơn hàng vào database thành công.
2. Ngay sau đó, hệ thống tự động gửi đơn sang hãng vận chuyển đã chọn (`carrier.id`).
3. Kết quả gửi sang hãng sẽ được trả về trong response cùng với `orderId`.

> **Lưu ý:**
>
> * Để gửi đơn thành công, cần đảm bảo `carrier.id` và `carrier.serviceId` hợp lệ (nên lấy từ API Rate).
> * Nếu gửi sang hãng thất bại nhưng đơn đã lưu thành công, response vẫn trả về `code: 1` với `orderId`, kèm thông báo lỗi trong `sendCarrierError`.

## Response

* Xem cấu trúc chung [tại đây](/v3/readme.md#response).

### Failed response

* Xem các mã lỗi chung [tại đây](/v3/readme.md#failed-response).

### Successful response

**Không gửi sang hãng (`sendCarrier = 0` hoặc không truyền):**

```json
{
  "code": 1,
  "data": {
    "orderId": "(int) ID đơn hàng trong hệ thống"
  },
  "messages": []
}
```

**Gửi sang hãng thành công (`sendCarrier = 1`):**

```json
{
  "code": 1,
  "data": {
    "orderId": " (int) ID đơn hàng trong hệ thống",
    "orderCode": "(string) Mã vận đơn trong hệ thống",
    "carrier": {
      "code": "(string) Mã vận đơn hãng vận chuyển",
      "totalFee": "(int) Phí ship",
      "declaredFee": "(int) Phí khai giá",
      "codFee": "(int) Phí thu tiền hộ"
    }
  },
  "messages": []
}
```

**Gửi sang hãng thất bại (`sendCarrier = 1` nhưng hãng trả lỗi):**

```json
{
  "code": 1,
  "data": {
    "orderId": "(int) ID đơn hàng trong hệ thống",
    "sendCarrierError": [
      "(string) Thông báo lỗi từ hãng vận chuyển"
    ]
  },
  "messages": [],
  "errorCode": null
}
```

> **Lưu ý:**
>
> * Response trả về `code: 1` (thành công) ngay cả khi gửi sang hãng thất bại, vì đơn hàng đã được lưu vào hệ thống thành công.
> * Client nên kiểm tra field `sendCarrierError` để biết có lỗi khi gửi sang hãng không.
> * Có thể gọi lại API [Gửi đơn sang hãng](/v3/ship/send.md) sau để thử gửi lại.
