# Tham chiếu: Vận đơn

Vận đơn, hành trình và huỷ vận đơn. Mọi đường dẫn dưới `https://danix.vn/api/open/v1`. Đặc tả máy đọc: [openapi.json](/openapi.json).

## Liệt kê vận đơn {#listShipments}

`GET /shipments`

Phân trang theo con trỏ. Dòng danh sách không có hành trình; lấy bằng `GET /shipments/{id}`.

**Quyền cần có:** khoá có quyền `pos.shipping.read` và quyền `pos.orders.read`.

**Tham số query**

| Tên | Kiểu | Bắt buộc | Mô tả |
| --- | --- | --- | --- |
| `limit` | integer | không | Số dòng mỗi trang, từ 1 đến 100. Mặc định 50. |
| `cursor` | string | không | Con trỏ lấy từ `nextCursor` của trang trước, để lật trang trong CÙNG một lượt đọc (giữ nguyên các tham số khác). Không tự dựng, không lưu để nối lượt đồng bộ sau. |
| `updatedSince` | string (date-time) | không | Chỉ lấy bản ghi có `updatedAt` từ thời điểm này (ISO 8601 UTC), tính cả mốc. Đây là cách đồng bộ tăng dần: có tham số này thì danh sách chỉ trả bản ghi đã qua khoảng trễ an toàn (trần thời gian tua lại kho của shop cộng 15 giây, mặc định 2 phút 15 giây). |
| `status` | "pending" \| "delivering" \| "delivered" \| "delivery_failed" \| "returning" \| "returned" \| "partially_returned" \| "cancelled" \| "lost" \| "damaged" \| "exception" \| "scrapped" | không | Chỉ lấy vận đơn ở trạng thái này. |
| `orderId` | string (uuid) | không | Chỉ lấy vận đơn của đơn này. |

**Ví dụ yêu cầu**

```bash
curl -X GET "https://danix.vn/api/open/v1/shipments" \
  -H "Authorization: Bearer dnx_live_…"
```

**Phản hồi mẫu (200)**

```json
{
  "data": [
    {
      "id": "018f3b8e-1c2d-7a4b-9c3d-000000001001",
      "carrier": "ghn",
      "trackingCode": "GHNABC123",
      "status": "delivering",
      "orderId": "018f3b8e-1c2d-7a4b-9c3d-000000000101",
      "orderCode": "DH1024",
      "codAmount": "480000",
      "feeTotal": "30000",
      "createdAt": "2026-10-02T03:15:00.000Z",
      "expectedDeliveryAt": null,
      "failReason": null,
      "updatedAt": "2026-10-02T03:15:00.000Z"
    }
  ],
  "nextCursor": null
}
```

**Trường của phản hồi**

| Trường | Kiểu | Bắt buộc | Mô tả |
| --- | --- | --- | --- |
| `data` | array<object> | có | Các bản ghi của trang này. |
| `data[].id` | string (uuid) | có | Mã vận đơn. |
| `data[].carrier` | "ghn" \| "vtp" | có | Hãng vận chuyển. |
| `data[].trackingCode` | string hoặc null | có | Mã vận đơn của hãng. Rỗng khi chưa đẩy sang hãng. |
| `data[].status` | "pending" \| "delivering" \| "delivered" \| "delivery_failed" \| "returning" \| "returned" \| "partially_returned" \| "cancelled" \| "lost" \| "damaged" \| "exception" \| "scrapped" | có | Trạng thái chuẩn của vận đơn. |
| `data[].orderId` | string (uuid) | có | Đơn hàng của vận đơn. |
| `data[].orderCode` | string | có | Mã đơn hàng. |
| `data[].codAmount` | string hoặc null | có | Tiền thu hộ (COD). Chuỗi thập phân hoặc `null`. |
| `data[].feeTotal` | string hoặc null | có | Tổng phí vận chuyển. Chuỗi thập phân hoặc `null`. |
| `data[].createdAt` | string (date-time) | có | Thời điểm tạo. ISO 8601, múi giờ UTC. |
| `data[].updatedAt` | string (date-time) | có | Lần sửa gần nhất. Danh sách sắp theo `(updatedAt, id)`; dùng làm mốc `updatedSince`. ISO 8601, múi giờ UTC. |
| `data[].expectedDeliveryAt` | string (date-time) hoặc null | có | Dự kiến giao. ISO 8601 UTC hoặc `null`. |
| `data[].failReason` | string hoặc null | có | Lý do giao thất bại, nếu có. |
| `nextCursor` | string hoặc null | có | Con trỏ của trang kế; `null` khi đã hết dữ liệu. |

**Lỗi**

| Trạng thái | Mã `code` | Ý nghĩa |
| --- | --- | --- |
| 401 | [`invalid-api-key`](/developers/errors#invalid-api-key) | Khoá API thiếu, sai hoặc đã bị thu hồi |
| 403 | [`insufficient-permission`](/developers/errors#insufficient-permission) | Khoá API không có quyền thực hiện thao tác này |
| 403 | [`shop-suspended`](/developers/errors#shop-suspended) | Shop đang bị đình chỉ |
| 403 | [`automation-not-active`](/developers/errors#automation-not-active) | Shop chưa bật tính năng Tự động hoá |
| 429 | [`rate-limited`](/developers/errors#rate-limited) | Vượt hạn mức gọi API, hãy chờ rồi thử lại |
| 500 | [`internal-error`](/developers/errors#internal-error) | Lỗi hệ thống |
| 400 | [`validation-failed`](/developers/errors#validation-failed) | Dữ liệu gửi lên không hợp lệ |
| 400 | [`invalid-cursor`](/developers/errors#invalid-cursor) | Con trỏ phân trang không hợp lệ |

Định dạng lỗi và bảng mọi mã `code`: [Lỗi](/developers/errors).

## Tạo vận đơn cho một đơn {#createShipment}

`POST /shipments`

Đẩy đơn sang hãng vận chuyển qua một kết nối đã cấu hình trong shop.

**Quyền cần có:** khoá có quyền `pos.shipping.read` và đủ các quyền `pos.orders.update`, `pos.products.read`.

**Thân yêu cầu (JSON)**

| Trường | Kiểu | Bắt buộc | Mô tả |
| --- | --- | --- | --- |
| `orderId` | string (uuid) | có | Đơn hàng cần giao. |
| `connectionId` | string (uuid) | có | Kết nối hãng vận chuyển của shop dùng để giao. |
| `weightGram` | integer | không | Khối lượng khai với hãng, gram, từ 1 tới 50000. |
| `codAmount` | string | không | Tiền thu hộ. Mặc định theo đơn. |
| `note` | string | không | Ghi chú cho hãng. |

**Ví dụ yêu cầu**

```bash
curl -X POST "https://danix.vn/api/open/v1/shipments" \
  -H "Authorization: Bearer dnx_live_…" \
  -H "Content-Type: application/json" \
  -d '{
  "orderId": "018f3b8e-1c2d-7a4b-9c3d-000000000101",
  "connectionId": "018f3b8e-1c2d-7a4b-9c3d-000000001301"
}'
```

**Phản hồi mẫu (201)**

```json
{
  "id": "018f3b8e-1c2d-7a4b-9c3d-000000001001",
  "carrier": "ghn",
  "trackingCode": "GHNABC123",
  "status": "delivering",
  "orderId": "018f3b8e-1c2d-7a4b-9c3d-000000000101",
  "orderCode": "DH1024",
  "codAmount": "480000",
  "feeTotal": "30000",
  "createdAt": "2026-10-02T03:15:00.000Z",
  "expectedDeliveryAt": null,
  "failReason": null,
  "recipientName": "Nguyễn Văn An",
  "recipientPhone": "0901234567",
  "recipientAddress": "12 Lê Lợi, Thạch Thang, Hải Châu, Đà Nẵng",
  "weightGram": 500,
  "pickedUpAt": "2026-10-02T03:15:00.000Z",
  "events": []
}
```

**Trường của phản hồi**

| Trường | Kiểu | Bắt buộc | Mô tả |
| --- | --- | --- | --- |
| `id` | string (uuid) | có | Mã vận đơn. |
| `carrier` | "ghn" \| "vtp" | có | Hãng vận chuyển. |
| `trackingCode` | string hoặc null | có | Mã vận đơn của hãng. Rỗng khi chưa đẩy sang hãng. |
| `status` | "pending" \| "delivering" \| "delivered" \| "delivery_failed" \| "returning" \| "returned" \| "partially_returned" \| "cancelled" \| "lost" \| "damaged" \| "exception" \| "scrapped" | có | Trạng thái chuẩn của vận đơn. |
| `orderId` | string (uuid) | có | Đơn hàng của vận đơn. |
| `orderCode` | string | có | Mã đơn hàng. |
| `codAmount` | string hoặc null | có | Tiền thu hộ (COD). Chuỗi thập phân hoặc `null`. |
| `feeTotal` | string hoặc null | có | Tổng phí vận chuyển. Chuỗi thập phân hoặc `null`. |
| `createdAt` | string (date-time) | có | Thời điểm tạo. ISO 8601, múi giờ UTC. |
| `expectedDeliveryAt` | string (date-time) hoặc null | có | Dự kiến giao. ISO 8601 UTC hoặc `null`. |
| `failReason` | string hoặc null | có | Lý do giao thất bại, nếu có. |
| `recipientName` | string hoặc null | có | Tên người nhận. |
| `recipientPhone` | string hoặc null | có | Số điện thoại người nhận. |
| `recipientAddress` | string hoặc null | có | Địa chỉ người nhận. |
| `weightGram` | integer hoặc null | có | Khối lượng khai với hãng, gram. |
| `pickedUpAt` | string (date-time) hoặc null | có | Thời điểm hãng lấy hàng. ISO 8601 UTC hoặc `null`. |
| `events` | array<object> | có | Hành trình, theo thứ tự thời gian. |
| `events[].id` | string (uuid) | có | Mã sự kiện. |
| `events[].status` | "pending" \| "delivering" \| "delivered" \| "delivery_failed" \| "returning" \| "returned" \| "partially_returned" \| "cancelled" \| "lost" \| "damaged" \| "exception" \| "scrapped" hoặc null | có | Trạng thái chuẩn sau sự kiện; `null` nếu sự kiện không đổi trạng thái. |
| `events[].carrierStatus` | string hoặc null | có | Mã trạng thái gốc của hãng. |
| `events[].occurredAt` | string (date-time) | có | Thời điểm hãng ghi nhận. ISO 8601, múi giờ UTC. |
| `events[].location` | string hoặc null | có | Nơi xảy ra. |
| `events[].description` | string hoặc null | có | Mô tả của hãng. |
| `events[].reason` | string hoặc null | có | Lý do (giao thất bại, hoàn…). |

**Lỗi**

| Trạng thái | Mã `code` | Ý nghĩa |
| --- | --- | --- |
| 401 | [`invalid-api-key`](/developers/errors#invalid-api-key) | Khoá API thiếu, sai hoặc đã bị thu hồi |
| 403 | [`insufficient-permission`](/developers/errors#insufficient-permission) | Khoá API không có quyền thực hiện thao tác này |
| 403 | [`shop-suspended`](/developers/errors#shop-suspended) | Shop đang bị đình chỉ |
| 403 | [`automation-not-active`](/developers/errors#automation-not-active) | Shop chưa bật tính năng Tự động hoá |
| 429 | [`rate-limited`](/developers/errors#rate-limited) | Vượt hạn mức gọi API, hãy chờ rồi thử lại |
| 500 | [`internal-error`](/developers/errors#internal-error) | Lỗi hệ thống |
| 402 | [`subscription-expired`](/developers/errors#subscription-expired) | Gói cước của shop đã hết hạn, chỉ còn quyền đọc |
| 400 | [`validation-failed`](/developers/errors#validation-failed) | Dữ liệu gửi lên không hợp lệ |
| 413 | [`payload-too-large`](/developers/errors#payload-too-large) | Thân yêu cầu vượt quá dung lượng cho phép |
| 415 | [`unsupported-media-type`](/developers/errors#unsupported-media-type) | Thân yêu cầu phải là JSON (`Content-Type: application/json`) |
| 404 | [`not-found`](/developers/errors#not-found) | Không tìm thấy tài nguyên |
| 409 | [`conflict`](/developers/errors#conflict) | Thao tác xung đột với trạng thái hiện tại |
| 422 | [`order-status-not-allowed`](/developers/errors#order-status-not-allowed) | Không chuyển được đơn sang trạng thái này từ trạng thái hiện tại |
| 422 | [`insufficient-stock`](/developers/errors#insufficient-stock) | Không đủ tồn kho cho thao tác này |
| 503 | [`carrier-unavailable`](/developers/errors#carrier-unavailable) | Hãng vận chuyển hiện không với tới được, hãy thử lại sau |

Định dạng lỗi và bảng mọi mã `code`: [Lỗi](/developers/errors).

## Chi tiết một vận đơn {#getShipment}

`GET /shipments/{id}`

Trả vận đơn kèm hành trình theo thứ tự thời gian.

**Quyền cần có:** khoá có quyền `pos.shipping.read` và quyền `pos.orders.read`.

**Tham số đường dẫn**

| Tên | Kiểu | Bắt buộc | Mô tả |
| --- | --- | --- | --- |
| `id` | string (uuid) | có | Mã định danh (UUID) của tài nguyên. |

**Ví dụ yêu cầu**

```bash
curl -X GET "https://danix.vn/api/open/v1/shipments/{id}" \
  -H "Authorization: Bearer dnx_live_…"
```

Thay `{id}` trong địa chỉ bằng mã thật của bản ghi, và `dnx_live_…` bằng khoá của bạn.

**Phản hồi mẫu (200)**

```json
{
  "id": "018f3b8e-1c2d-7a4b-9c3d-000000001001",
  "carrier": "ghn",
  "trackingCode": "GHNABC123",
  "status": "delivering",
  "orderId": "018f3b8e-1c2d-7a4b-9c3d-000000000101",
  "orderCode": "DH1024",
  "codAmount": "480000",
  "feeTotal": "30000",
  "createdAt": "2026-10-02T03:15:00.000Z",
  "expectedDeliveryAt": null,
  "failReason": null,
  "recipientName": "Nguyễn Văn An",
  "recipientPhone": "0901234567",
  "recipientAddress": "12 Lê Lợi, Thạch Thang, Hải Châu, Đà Nẵng",
  "weightGram": 500,
  "pickedUpAt": "2026-10-02T03:15:00.000Z",
  "events": []
}
```

**Trường của phản hồi**

| Trường | Kiểu | Bắt buộc | Mô tả |
| --- | --- | --- | --- |
| `id` | string (uuid) | có | Mã vận đơn. |
| `carrier` | "ghn" \| "vtp" | có | Hãng vận chuyển. |
| `trackingCode` | string hoặc null | có | Mã vận đơn của hãng. Rỗng khi chưa đẩy sang hãng. |
| `status` | "pending" \| "delivering" \| "delivered" \| "delivery_failed" \| "returning" \| "returned" \| "partially_returned" \| "cancelled" \| "lost" \| "damaged" \| "exception" \| "scrapped" | có | Trạng thái chuẩn của vận đơn. |
| `orderId` | string (uuid) | có | Đơn hàng của vận đơn. |
| `orderCode` | string | có | Mã đơn hàng. |
| `codAmount` | string hoặc null | có | Tiền thu hộ (COD). Chuỗi thập phân hoặc `null`. |
| `feeTotal` | string hoặc null | có | Tổng phí vận chuyển. Chuỗi thập phân hoặc `null`. |
| `createdAt` | string (date-time) | có | Thời điểm tạo. ISO 8601, múi giờ UTC. |
| `expectedDeliveryAt` | string (date-time) hoặc null | có | Dự kiến giao. ISO 8601 UTC hoặc `null`. |
| `failReason` | string hoặc null | có | Lý do giao thất bại, nếu có. |
| `recipientName` | string hoặc null | có | Tên người nhận. |
| `recipientPhone` | string hoặc null | có | Số điện thoại người nhận. |
| `recipientAddress` | string hoặc null | có | Địa chỉ người nhận. |
| `weightGram` | integer hoặc null | có | Khối lượng khai với hãng, gram. |
| `pickedUpAt` | string (date-time) hoặc null | có | Thời điểm hãng lấy hàng. ISO 8601 UTC hoặc `null`. |
| `events` | array<object> | có | Hành trình, theo thứ tự thời gian. |
| `events[].id` | string (uuid) | có | Mã sự kiện. |
| `events[].status` | "pending" \| "delivering" \| "delivered" \| "delivery_failed" \| "returning" \| "returned" \| "partially_returned" \| "cancelled" \| "lost" \| "damaged" \| "exception" \| "scrapped" hoặc null | có | Trạng thái chuẩn sau sự kiện; `null` nếu sự kiện không đổi trạng thái. |
| `events[].carrierStatus` | string hoặc null | có | Mã trạng thái gốc của hãng. |
| `events[].occurredAt` | string (date-time) | có | Thời điểm hãng ghi nhận. ISO 8601, múi giờ UTC. |
| `events[].location` | string hoặc null | có | Nơi xảy ra. |
| `events[].description` | string hoặc null | có | Mô tả của hãng. |
| `events[].reason` | string hoặc null | có | Lý do (giao thất bại, hoàn…). |

**Lỗi**

| Trạng thái | Mã `code` | Ý nghĩa |
| --- | --- | --- |
| 401 | [`invalid-api-key`](/developers/errors#invalid-api-key) | Khoá API thiếu, sai hoặc đã bị thu hồi |
| 403 | [`insufficient-permission`](/developers/errors#insufficient-permission) | Khoá API không có quyền thực hiện thao tác này |
| 403 | [`shop-suspended`](/developers/errors#shop-suspended) | Shop đang bị đình chỉ |
| 403 | [`automation-not-active`](/developers/errors#automation-not-active) | Shop chưa bật tính năng Tự động hoá |
| 429 | [`rate-limited`](/developers/errors#rate-limited) | Vượt hạn mức gọi API, hãy chờ rồi thử lại |
| 500 | [`internal-error`](/developers/errors#internal-error) | Lỗi hệ thống |
| 404 | [`not-found`](/developers/errors#not-found) | Không tìm thấy tài nguyên |

Định dạng lỗi và bảng mọi mã `code`: [Lỗi](/developers/errors).

## Huỷ vận đơn {#cancelShipment}

`POST /shipments/{id}/cancel`

Huỷ vận đơn chưa kết thúc. Vận đơn đã giao hay đã hoàn không huỷ được.

**Quyền cần có:** khoá có quyền `pos.shipping.read` và quyền `pos.orders.update`.

**Tham số đường dẫn**

| Tên | Kiểu | Bắt buộc | Mô tả |
| --- | --- | --- | --- |
| `id` | string (uuid) | có | Mã định danh (UUID) của tài nguyên. |

**Thân yêu cầu (JSON)**

| Trường | Kiểu | Bắt buộc | Mô tả |
| --- | --- | --- | --- |
| `reason` | string | không | Lý do huỷ, lưu vào nhật ký. |

**Ví dụ yêu cầu**

```bash
curl -X POST "https://danix.vn/api/open/v1/shipments/{id}/cancel" \
  -H "Authorization: Bearer dnx_live_…" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "Khách đổi ý"
}'
```

Thay `{id}` trong địa chỉ bằng mã thật của bản ghi, và `dnx_live_…` bằng khoá của bạn.

**Phản hồi mẫu (200)**

```json
{
  "id": "018f3b8e-1c2d-7a4b-9c3d-000000001001",
  "carrier": "ghn",
  "trackingCode": "GHNABC123",
  "status": "delivering",
  "orderId": "018f3b8e-1c2d-7a4b-9c3d-000000000101",
  "orderCode": "DH1024",
  "codAmount": "480000",
  "feeTotal": "30000",
  "createdAt": "2026-10-02T03:15:00.000Z",
  "expectedDeliveryAt": null,
  "failReason": null,
  "recipientName": "Nguyễn Văn An",
  "recipientPhone": "0901234567",
  "recipientAddress": "12 Lê Lợi, Thạch Thang, Hải Châu, Đà Nẵng",
  "weightGram": 500,
  "pickedUpAt": "2026-10-02T03:15:00.000Z",
  "events": []
}
```

**Trường của phản hồi**

| Trường | Kiểu | Bắt buộc | Mô tả |
| --- | --- | --- | --- |
| `id` | string (uuid) | có | Mã vận đơn. |
| `carrier` | "ghn" \| "vtp" | có | Hãng vận chuyển. |
| `trackingCode` | string hoặc null | có | Mã vận đơn của hãng. Rỗng khi chưa đẩy sang hãng. |
| `status` | "pending" \| "delivering" \| "delivered" \| "delivery_failed" \| "returning" \| "returned" \| "partially_returned" \| "cancelled" \| "lost" \| "damaged" \| "exception" \| "scrapped" | có | Trạng thái chuẩn của vận đơn. |
| `orderId` | string (uuid) | có | Đơn hàng của vận đơn. |
| `orderCode` | string | có | Mã đơn hàng. |
| `codAmount` | string hoặc null | có | Tiền thu hộ (COD). Chuỗi thập phân hoặc `null`. |
| `feeTotal` | string hoặc null | có | Tổng phí vận chuyển. Chuỗi thập phân hoặc `null`. |
| `createdAt` | string (date-time) | có | Thời điểm tạo. ISO 8601, múi giờ UTC. |
| `expectedDeliveryAt` | string (date-time) hoặc null | có | Dự kiến giao. ISO 8601 UTC hoặc `null`. |
| `failReason` | string hoặc null | có | Lý do giao thất bại, nếu có. |
| `recipientName` | string hoặc null | có | Tên người nhận. |
| `recipientPhone` | string hoặc null | có | Số điện thoại người nhận. |
| `recipientAddress` | string hoặc null | có | Địa chỉ người nhận. |
| `weightGram` | integer hoặc null | có | Khối lượng khai với hãng, gram. |
| `pickedUpAt` | string (date-time) hoặc null | có | Thời điểm hãng lấy hàng. ISO 8601 UTC hoặc `null`. |
| `events` | array<object> | có | Hành trình, theo thứ tự thời gian. |
| `events[].id` | string (uuid) | có | Mã sự kiện. |
| `events[].status` | "pending" \| "delivering" \| "delivered" \| "delivery_failed" \| "returning" \| "returned" \| "partially_returned" \| "cancelled" \| "lost" \| "damaged" \| "exception" \| "scrapped" hoặc null | có | Trạng thái chuẩn sau sự kiện; `null` nếu sự kiện không đổi trạng thái. |
| `events[].carrierStatus` | string hoặc null | có | Mã trạng thái gốc của hãng. |
| `events[].occurredAt` | string (date-time) | có | Thời điểm hãng ghi nhận. ISO 8601, múi giờ UTC. |
| `events[].location` | string hoặc null | có | Nơi xảy ra. |
| `events[].description` | string hoặc null | có | Mô tả của hãng. |
| `events[].reason` | string hoặc null | có | Lý do (giao thất bại, hoàn…). |

**Lỗi**

| Trạng thái | Mã `code` | Ý nghĩa |
| --- | --- | --- |
| 401 | [`invalid-api-key`](/developers/errors#invalid-api-key) | Khoá API thiếu, sai hoặc đã bị thu hồi |
| 403 | [`insufficient-permission`](/developers/errors#insufficient-permission) | Khoá API không có quyền thực hiện thao tác này |
| 403 | [`shop-suspended`](/developers/errors#shop-suspended) | Shop đang bị đình chỉ |
| 403 | [`automation-not-active`](/developers/errors#automation-not-active) | Shop chưa bật tính năng Tự động hoá |
| 429 | [`rate-limited`](/developers/errors#rate-limited) | Vượt hạn mức gọi API, hãy chờ rồi thử lại |
| 500 | [`internal-error`](/developers/errors#internal-error) | Lỗi hệ thống |
| 402 | [`subscription-expired`](/developers/errors#subscription-expired) | Gói cước của shop đã hết hạn, chỉ còn quyền đọc |
| 400 | [`validation-failed`](/developers/errors#validation-failed) | Dữ liệu gửi lên không hợp lệ |
| 413 | [`payload-too-large`](/developers/errors#payload-too-large) | Thân yêu cầu vượt quá dung lượng cho phép |
| 415 | [`unsupported-media-type`](/developers/errors#unsupported-media-type) | Thân yêu cầu phải là JSON (`Content-Type: application/json`) |
| 404 | [`not-found`](/developers/errors#not-found) | Không tìm thấy tài nguyên |
| 409 | [`shipment-not-cancellable`](/developers/errors#shipment-not-cancellable) | Vận đơn không còn huỷ được |
| 503 | [`carrier-unavailable`](/developers/errors#carrier-unavailable) | Hãng vận chuyển hiện không với tới được, hãy thử lại sau |

Định dạng lỗi và bảng mọi mã `code`: [Lỗi](/developers/errors).
