# Create Order

## Endpoint

| Environment | 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 | Required | Description |
| --- | --- | --- |
| `Content-Type` | Yes | `application/json` |
| `Token` | Yes | Shop token (issued by GHN) — [get a token](https://developer.ghn.vn/en/docs/token/get-token.md) |
| `ShopId` | Yes | Shop ID (int) |

## Parameters

- **to_name** (String): Recipient name. Max 1024 characters
- **to_phone** (String): Recipient phone
- **to_address** (String): Recipient full address. Max 1024 characters
- **to_ward_name** (String): Recipient ward name
- **to_district_name** (String): Recipient district name. **Required when `is_new_to_address` = false**; leave empty when `true` (new units have no district level)
- **to_province_name** (String): Recipient province/city name
- **is_new_to_address** (Bool): Which address scheme the recipient address fields use. On **01/07/2025** Vietnam restructured its administrative units: provinces and wards were merged and the district level was removed. Both schemes use the same address fields — this flag tells GHN which one you sent:<br>`false` (default): old units (ward + district + province)<br>`true`: new units (ward + province)
- **from_name** (String): Sender name. Default: the shop profile on `ShopId`. Max 1024 characters
- **from_phone** (String): Sender phone. Default: the shop profile
- **from_hotline** (String): Sender hotline. Default: none
- **from_address** (String): Sender full address. Default: the shop address. Max 1024 characters
- **from_ward_name** (String): Sender ward name. Default: the shop address
- **from_district_name** (String): Sender district name. Default: the shop address
- **from_province_name** (String): Sender province/city name. Default: the shop address
- **is_new_from_address** (Bool): Same rule as `is_new_to_address`, applied to the sender address block. Default: `false`
- **return_name** (String): Return recipient name. Default: the sender. Max 1024 characters
- **return_phone** (String): Return contact phone. Default: the sender phone
- **return_address** (String): Return full address. Default: the shop's default warehouse address (Dashboard). Max 1024 characters
- **return_ward_name** (String): Return ward name
- **return_district_name** (String): Return district name (see `is_new_to_address`)
- **return_province_name** (String): Return province/city name
- **is_new_return_address** (Bool): Same rule as `is_new_to_address`, applied to the return address block. Default: `false`
- **client_order_code** (String): Shop's internal order code (unique per shop). Max 50. Default: `null`. Makes retries safe: re-sending a request with an already-used code returns the **previously created** `order_code` instead of creating a duplicate order
- **weight** (Int): Weight (grams). Maximum: `50,000`
- **length** (Int): Length (cm). Maximum: `200`
- **width** (Int): Width (cm). Maximum: `200`
- **height** (Int): Height (cm). Maximum: `200`
- **content** (String): Goods description. Max 2000. Default: generated from `items[]` names/quantities
- **service_id** (Int): Delivery service ID from [Get Service](https://developer.ghn.vn/en/docs/master-data/get-service.md). Default: `0` → the system auto-picks based on `service_type_id` and the route
- **service_type_id** (Int): Service type, chosen by weight:<br>`2`: total weight **under 20 kg**<br>`5`: total weight **20 kg or more**, or multi-parcel orders
- **payment_type_id** (Int): Who pays the shipping fee:<br>`1`: Shop/Seller<br>`2`: Buyer/Recipient
- **coupon** (String): Promotion code. Default: none
- **cod_amount** (Int): Cash-on-Delivery amount to collect from the recipient (VND). Maximum: `50,000,000`. Default: `0`
- **cod_failed_amount** (Int): Amount collected from the recipient when delivery fails (VND). Default: `0`
- **insurance_value** (Int): Declared insurance value (VND). Maximum: `5,000,000`. Default: `0`
- **order_value** (Int): Order value (VND). Default: `0`
- **required_note** (String): Delivery instruction — one of:<br>`KHONGCHOXEMHANG`: recipient may NOT open/inspect the parcel<br>`CHOXEMHANGKHONGTHU`: recipient may inspect but not try the goods<br>`CHOTHUHANG`: recipient may inspect and try the goods
- **note** (String): Note to the shipper. Max 5000. Default: none
- **pick_station_id** (Int): How the parcel enters GHN's network:<br>`0`: pickup — GHN picks up the parcel at the shop address (default)<br>`1`: drop off — the shop drops the parcel off at a GHN post office
- **pick_shift** (Int[]): List of pickup shift IDs (use [Pick Shift](https://developer.ghn.vn/en/docs/master-data/pick-shift.md)). Default: earliest shift
- **items** (Object[]): List of products (structure below). **Required when `service_type_id=5`** — used to compute per-parcel fees. For `service_type_id=2` it is optional but recommended

### items[] structure

- **name** (String): Product name
- **code** (String): Product code. Default: none
- **quantity** (Int): Quantity
- **price** (Int): Product price (VND). Default: none
- **length** (Int): Length (cm). **Required when `service_type_id=5`**
- **width** (Int): Width (cm). **Required when `service_type_id=5`**
- **height** (Int): Height (cm). **Required when `service_type_id=5`**
- **weight** (Int): Weight (grams). **Required when `service_type_id=5`**

> **NOTE**
> **Note**: With `service_type_id=5` (total weight ≥ 20 kg or multi-parcel), the system computes fees per parcel from `items[]`, so each item's `length`, `width`, `height`, and `weight` are required. With `service_type_id=2` (under 20 kg), only the order-level dimensions (`weight`, `length`, `width`, `height` at the root) are required.

## Request Example

```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": "GHN Shirt Shop",
    "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": "GHN Shirt Shop Warehouse",
    "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": "Tran 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": "GHN unisex t-shirt - 2 pcs",
    "note": "Call before delivery",
    "weight": 600,
    "length": 25,
    "width": 20,
    "height": 8,
    "pick_shift": [2],
    "items": [
      {
        "name": "GHN t-shirt 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": "Tran 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": "GHN unisex t-shirt - 2 pcs",
    "weight": 600,
    "length": 25,
    "width": 20,
    "height": 8,
    "service_type_id": 2,
    "items": [
      { "name": "GHN t-shirt size M", "quantity": 2, "weight": 300 }
    ]
  }'
```

## Response

### Success (HTTP 200)

_Captured from a real Staging-environment call._

```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"
  }
}
```

### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `code` | Int | HTTP code (`200` on success) |
| `message` | String | Result message (`Success`) |
| `message_display` | String | Human-readable Vietnamese success message |
| `data.order_code` | String | **GHN tracking number** — used by all subsequent APIs (detail, update, cancel, fee, …). The status webhook starts firing as soon as this code is generated |
| `data.fee` | Object | Fee breakdown (VND): `main_service` (shipping), `insurance`, `cod_fee`, `station_do` (delivery at post office), `station_pu` (pickup at post office), `return`, `r2s` (return to sender), `return_again`, `coupon` (discount, negative), `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 | Total fee (VND) |
| `data.expected_delivery_time` | String | Expected delivery time (ISO 8601) |

### Validation error (HTTP 400)

_Captured from a real Staging-environment call (invalid `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."
}
```

### Route not found

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

## Error Codes

| code_message | HTTP | When |
| --- | --- | --- |
| `USER_ERR_COMMON` | 400 | Validation failure / missing required field / invalid `required_note` |
| `PHONE_INVALID` | 400 | Sender or recipient phone is malformed |
| `CLIENT_NOT_OWNER_OF_SHOP` | 400 | Token does not own the shop |
| `ROUTE_NOT_FOUND_SERVICE` | 400 | No route exists for the pickup → delivery district pair with the chosen `service_id` |
| `SERVICE_NOT_FOUND_CONFIG_FEE` | 400 | `service_id` has no fee config |
| `SERVER_ERROR_COMMON` | 500 | Internal error |
