# Tạo đơn

## Endpoint

| Môi trường | URL |
| --- | --- |
| Production | `https://online-gateway.ghn.vn/shiip/public-api/v2/shipping-order/create` |
| Staging | `https://dev-online-gateway.ghn.vn/shiip/public-api/v2/shipping-order/create` |

**Method**: `POST`

## Headers

| Header | Bắt buộc | Mô tả |
| --- | --- | --- |
| `Content-Type` | Có | `application/json` |
| `Token` | Có | Token của shop (do GHN cấp) — [lấy token](https://developer.ghn.vn/vi/docs/token/get-token.md) |
| `ShopId` | Có | Shop ID (số nguyên) |

## Tham số

- **to_name** (String): Tên người nhận. Tối đa 1024 ký tự
- **to_phone** (String): Số điện thoại người nhận
- **to_address** (String): Địa chỉ đầy đủ người nhận. Tối đa 1024 ký tự
- **to_ward_name** (String): Tên phường/xã người nhận
- **to_district_name** (String): Tên quận/huyện người nhận. **Bắt buộc khi `is_new_to_address` = false**; để trống khi `true` (đơn vị hành chính mới không còn cấp quận/huyện)
- **to_province_name** (String): Tên tỉnh/thành phố người nhận
- **is_new_to_address** (Bool): Cho biết khối địa chỉ người nhận dùng hệ đơn vị hành chính nào. Ngày **01/07/2025** Việt Nam sắp xếp lại đơn vị hành chính: sáp nhập tỉnh và phường/xã, bỏ cấp quận/huyện. Cả hai hệ đều dùng chung các trường địa chỉ — cờ này báo cho GHN biết bạn gửi theo hệ nào:<br>`false` (mặc định): đơn vị cũ (phường/xã + quận/huyện + tỉnh)<br>`true`: đơn vị mới (phường/xã + tỉnh)
- **from_name** (String): Tên người gửi. Mặc định: theo hồ sơ shop của `ShopId`. Tối đa 1024 ký tự
- **from_phone** (String): SĐT người gửi. Mặc định: theo hồ sơ shop
- **from_hotline** (String): Hotline người gửi. Mặc định: không có
- **from_address** (String): Địa chỉ đầy đủ người gửi. Mặc định: địa chỉ shop. Tối đa 1024 ký tự
- **from_ward_name** (String): Tên phường/xã người gửi. Mặc định: địa chỉ shop
- **from_district_name** (String): Tên quận/huyện người gửi. Mặc định: địa chỉ shop
- **from_province_name** (String): Tên tỉnh/thành người gửi. Mặc định: địa chỉ shop
- **is_new_from_address** (Bool): Cùng quy tắc như `is_new_to_address`, áp dụng cho khối địa chỉ người gửi. Mặc định: `false`
- **return_name** (String): Tên người nhận hàng trả. Mặc định: người gửi. Tối đa 1024 ký tự
- **return_phone** (String): SĐT liên hệ trả hàng. Mặc định: SĐT người gửi
- **return_address** (String): Địa chỉ đầy đủ trả hàng. Mặc định: địa chỉ kho mặc định của shop (trên Dashboard). Tối đa 1024 ký tự
- **return_ward_name** (String): Tên phường/xã trả hàng
- **return_district_name** (String): Tên quận/huyện trả hàng (xem `is_new_to_address`)
- **return_province_name** (String): Tên tỉnh/thành trả hàng
- **is_new_return_address** (Bool): Cùng quy tắc như `is_new_to_address`, áp dụng cho khối địa chỉ trả hàng. Mặc định: `false`
- **client_order_code** (String): Mã đơn nội bộ của shop (duy nhất theo shop). Tối đa 50. Mặc định: `null`. Giúp gọi lại an toàn: gửi lại request với mã đã dùng sẽ trả về `order_code` **đã tạo trước đó** thay vì tạo đơn trùng
- **weight** (Int): Khối lượng (gram). Tối đa: `50,000`
- **length** (Int): Chiều dài (cm). Tối đa: `200`
- **width** (Int): Chiều rộng (cm). Tối đa: `200`
- **height** (Int): Chiều cao (cm). Tối đa: `200`
- **content** (String): Mô tả hàng hóa. Tối đa 2000. Mặc định: tự sinh từ tên/số lượng trong `items[]`
- **service_id** (Int): Mã dịch vụ vận chuyển, lấy từ [Lấy Dịch vụ](https://developer.ghn.vn/vi/docs/master-data/get-service.md). Mặc định: `0` → hệ thống tự chọn theo `service_type_id` và tuyến
- **service_type_id** (Int): Loại dịch vụ, chọn theo khối lượng:<br>`2`: tổng khối lượng **dưới 20 kg**<br>`5`: tổng khối lượng **từ 20 kg trở lên**, hoặc đơn nhiều kiện
- **payment_type_id** (Int): Bên trả phí vận chuyển:<br>`1`: Shop/Người bán<br>`2`: Người mua/Người nhận
- **coupon** (String): Mã khuyến mãi. Mặc định: không có
- **cod_amount** (Int): Số tiền thu hộ (COD) từ người nhận (VND). Tối đa: `50,000,000`. Mặc định: `0`
- **cod_failed_amount** (Int): Số tiền thu từ người nhận khi giao thất bại (VND). Mặc định: `0`
- **insurance_value** (Int): Giá trị khai giá bảo hiểm (VND). Tối đa: `5,000,000`. Mặc định: `0`
- **order_value** (Int): Giá trị đơn hàng (VND). Mặc định: `0`
- **required_note** (String): Ghi chú giao hàng — một trong các giá trị:<br>`KHONGCHOXEMHANG`: người nhận KHÔNG được mở/xem hàng<br>`CHOXEMHANGKHONGTHU`: người nhận được xem hàng nhưng không được thử<br>`CHOTHUHANG`: người nhận được xem và thử hàng
- **note** (String): Ghi chú cho tài xế. Tối đa 5000. Mặc định: không có
- **pick_station_id** (Int): Cách hàng vào mạng lưới GHN:<br>`0`: lấy hàng — GHN đến lấy tại địa chỉ shop (mặc định)<br>`1`: gửi tại bưu cục — shop mang hàng đến bưu cục GHN
- **pick_shift** (Int[]): Danh sách mã ca lấy hàng (dùng [Ca lấy hàng](https://developer.ghn.vn/vi/docs/master-data/pick-shift.md)). Mặc định: ca sớm nhất
- **items** (Object[]): Danh sách sản phẩm (cấu trúc bên dưới). **Bắt buộc khi `service_type_id=5`** — dùng để tính phí theo từng kiện. Với `service_type_id=2` thì không bắt buộc nhưng nên có

### Cấu trúc items[]

- **name** (String): Tên sản phẩm
- **code** (String): Mã sản phẩm. Mặc định: không có
- **quantity** (Int): Số lượng
- **price** (Int): Giá sản phẩm (VND). Mặc định: không có
- **length** (Int): Chiều dài (cm). **Bắt buộc khi `service_type_id=5`**
- **width** (Int): Chiều rộng (cm). **Bắt buộc khi `service_type_id=5`**
- **height** (Int): Chiều cao (cm). **Bắt buộc khi `service_type_id=5`**
- **weight** (Int): Khối lượng (gram). **Bắt buộc khi `service_type_id=5`**

> **NOTE**
> **Lưu ý**: Với `service_type_id=5` (tổng khối lượng ≥ 20 kg hoặc nhiều kiện), hệ thống tính phí theo từng kiện từ `items[]`, nên mỗi item bắt buộc có `length`, `width`, `height`, `weight`. Với `service_type_id=2` (dưới 20 kg), chỉ cần kích thước ở cấp đơn hàng (`weight`, `length`, `width`, `height` ở gốc).

## Ví dụ Request

```bash
curl -X POST https://dev-online-gateway.ghn.vn/shiip/public-api/v2/shipping-order/create \
  -H "Token: 5c1d8a9e-2f4b-11ed-..." \
  -H "ShopId: 92837" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_type_id": 2,
    "required_note": "CHOXEMHANGKHONGTHU",
    "client_order_code": "SHOP-2026-00193",
    "from_name": "Shop Áo GHN",
    "from_phone": "0332190444",
    "from_address": "39 Nguyễn Thị Thập, Phường Tân Phú, Quận 7, TP. Hồ Chí Minh",
    "from_ward_name": "Phường Tân Phú",
    "from_district_name": "Quận 7",
    "from_province_name": "TP. Hồ Chí Minh",
    "return_name": "Kho Shop Áo GHN",
    "return_phone": "0332190444",
    "return_address": "39 Nguyễn Thị Thập, Phường Tân Phú, Quận 7, TP. Hồ Chí Minh",
    "return_ward_name": "Phường Tân Phú",
    "return_district_name": "Quận 7",
    "return_province_name": "TP. Hồ Chí Minh",
    "to_name": "Trần Minh Anh",
    "to_phone": "0987654321",
    "to_address": "72 Lê Thánh Tôn, P. Bến Nghé, Quận 1, TP. Hồ Chí Minh",
    "to_ward_name": "Phường Bến Nghé",
    "to_district_name": "Quận 1",
    "to_province_name": "TP. Hồ Chí Minh",
    "cod_amount": 285000,
    "cod_failed_amount": 0,
    "insurance_value": 285000,
    "order_value": 285000,
    "coupon": null,
    "service_id": 0,
    "service_type_id": 2,
    "content": "Áo thun unisex GHN - 2 chiếc",
    "note": "Gọi trước khi giao",
    "weight": 600,
    "length": 25,
    "width": 20,
    "height": 8,
    "pick_shift": [2],
    "items": [
      {
        "name": "Áo thun GHN size M",
        "code": "GHN-TS-M-BLK",
        "quantity": 2,
        "price": 142500,
        "length": 12,
        "width": 12,
        "height": 12,
        "weight": 300
      }
    ]
  }'
```

```bash
curl -X POST https://dev-online-gateway.ghn.vn/shiip/public-api/v2/shipping-order/create \
  -H "Token: 5c1d8a9e-2f4b-11ed-..." \
  -H "ShopId: 92837" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_type_id": 2,
    "required_note": "CHOXEMHANGKHONGTHU",
    "to_name": "Trần Minh Anh",
    "to_phone": "0987654321",
    "to_address": "72 Lê Thánh Tôn, Phường Sài Gòn, TP. Hồ Chí Minh",
    "to_ward_name": "Phường Sài Gòn",
    "to_province_name": "Hồ Chí Minh",
    "is_new_to_address": true,
    "content": "Áo thun unisex GHN - 2 chiếc",
    "weight": 600,
    "length": 25,
    "width": 20,
    "height": 8,
    "service_type_id": 2,
    "items": [
      { "name": "Áo thun GHN size M", "quantity": 2, "weight": 300 }
    ]
  }'
```

## Response

### Thành công (HTTP 200)

_Lấy từ một lần gọi thật trên môi trường Staging._

```json
{
  "code": 200,
  "message": "Success",
  "message_display": "Tạo đơn hàng thành công. Mã đơn hàng: LADFYR",
  "code_message_value": "",
  "data": {
    "order_code": "LADFYR",
    "fee": {
      "main_service": 20900,
      "insurance": 0,
      "cod_fee": 0,
      "station_do": 0,
      "station_pu": 0,
      "return": 0,
      "r2s": 0,
      "return_again": 0,
      "coupon": 0,
      "document_return": 0,
      "double_check": 0,
      "double_check_deliver": 0,
      "pick_remote_areas_fee": 0,
      "deliver_remote_areas_fee": 0,
      "pick_remote_areas_fee_return": 0,
      "deliver_remote_areas_fee_return": 0,
      "cod_failed_fee": 0,
      "change_to_address_fee": 0,
      "change_return_address_fee": 0
    },
    "total_fee": 20900,
    "expected_delivery_time": "2026-07-15T16:59:59Z"
  }
}
```

### Các trường Response

| Trường | Kiểu | Mô tả |
| --- | --- | --- |
| `code` | Int | Mã HTTP (`200` nếu thành công) |
| `message` | String | Thông báo kết quả (`Success`) |
| `message_display` | String | Thông báo thành công dạng chữ (tiếng Việt) |
| `data.order_code` | String | **Mã vận đơn GHN** — dùng cho mọi API sau này (chi tiết, cập nhật, hủy, phí, …). Webhook trạng thái bắt đầu bắn ngay khi có mã này |
| `data.fee` | Object | Chi tiết phí (VND): `main_service` (phí vận chuyển), `insurance` (bảo hiểm), `cod_fee`, `station_do` (giao tại bưu cục), `station_pu` (lấy tại bưu cục), `return`, `r2s` (trả về người gửi), `return_again`, `coupon` (giảm giá, số âm), `document_return`, `double_check`, `double_check_deliver`, `pick_remote_areas_fee`, `deliver_remote_areas_fee`, `pick_remote_areas_fee_return`, `deliver_remote_areas_fee_return`, `cod_failed_fee`, `change_to_address_fee`, `change_return_address_fee` |
| `data.total_fee` | Int | Tổng phí (VND) |
| `data.expected_delivery_time` | String | Thời gian giao dự kiến (ISO 8601) |

### Lỗi xác thực (HTTP 400)

_Lấy từ một lần gọi thật trên môi trường Staging (sai `required_note`)._

```json
{
  "code": 400,
  "message": "Sai thông tin Required Note",
  "data": null,
  "code_message": "USER_ERR_COMMON",
  "code_message_value": "Sai thông tin đầu vào. Vui lòng thử lại."
}
```

### Không tìm thấy tuyến

```json
{
  "code": 400,
  "message": "calculate fee error: calculate service fee error: route not found service",
  "data": null
}
```

## Bảng mã lỗi

| code_message | HTTP | Khi nào |
| --- | --- | --- |
| `USER_ERR_COMMON` | 400 | Lỗi xác thực / thiếu trường bắt buộc / `required_note` không hợp lệ |
| `PHONE_INVALID` | 400 | SĐT người gửi hoặc người nhận sai định dạng |
| `CLIENT_NOT_OWNER_OF_SHOP` | 400 | Token không sở hữu shop |
| `ROUTE_NOT_FOUND_SERVICE` | 400 | Không có tuyến cho cặp quận/huyện lấy → giao với `service_id` đã chọn |
| `SERVICE_NOT_FOUND_CONFIG_FEE` | 400 | `service_id` chưa có cấu hình phí |
| `SERVER_ERROR_COMMON` | 500 | Lỗi hệ thống |
