Chuyển tới nội dung chính

API Đơn hàng


Tạo đơn hàng​

MethodPOST
URL/api/order/create-order

Body request

{
"address_id": 2,
"consignee_name": "sarenda mcguire",
"consignee_phone": "",
"consignee_address": "6105 W Elmwood Dr",
"consignee_address_other": "",
"consignee_country": "US",
"consignee_city": "Wildomar",
"consignee_postal_code": "57718",
"consignee_state_code": "SD",
"order_number": "DEV123456789",
"product_name": "Metal",
"product_price": 5.5,
"length": 1.93,
"width": 108,
"height": 1.9,
"weight": 1.1,
"service_code": "EPK",
"service_add": "",
"money_collection": 0,
"order_code_upstream_partner": "partner_of_partner",
"package_option": "818",
"unit_type": "cm-g",
"label_sender": "WRIGLEYS Cool Air",
"mode": null
}

Giải thích

No.Field NameData TypeDescription
1address_idLongMã kho hàng (3.1)
2consignee_nameStringHọ tên người nhận
3consignee_phoneStringSố điện thoại người nhận
4consignee_addressStringĐịa chỉ người nhận 1
5consignee_address_otherStringĐịa chỉ người nhận 2
6consignee_countryStringMã quốc gia (fix: US)
7consignee_cityStringTỉnh / thành phố (3.2)
8consignee_postal_codeString5 chữ số (người dùng nhập)
9consignee_state_codeStringState code (3.2)
10order_numberStringMã đơn hàng của đối tác
11product_nameStringNội dung hàng hóa
12product_priceDecimalGiá trị hàng hóa
13lengthDecimalChiều dài (cm)
14widthDecimalChiều rộng (cm)
15heightDecimalChiều cao (cm)
16weightDecimalTrọng lượng (gram)
17service_codeStringDịch vụ chính (liên hệ)
18service_addStringDịch vụ gia tăng
19money_collectionDecimalSố tiền thu hộ
20order_code_upstream_partnerStringMã đối tác của đối tác
21package_optionStringPin lithium: 818 (Marked), 820 (Unmarked). Với dịch vụ LBE6 dùng mã đầy đủ: 8181, 8182, 8201, 8202. Bỏ trống nếu không có PIN
22unit_typeStringĐơn vị của các chiều và cân nặng. Mặc định không điền là cm-g (mm-g,cm-g,cm-kg,in-lb)
23label_senderStringField này bổ sung tên đại lý người gửi, nếu không set thì lấy mặc định trong label_sender trong customer đã set
24modeStringTruyền "advanced" để dùng Advanced Mode (xem mục bên dưới). Bỏ trống hoặc null cho Simple Mode

Validation Rules​

thông tin

service_code cần liên hệ để lấy danh sách dịch vụ khả dụng. Danh sách service phải tồn tại trong hệ thống BELL.

address_id​

  • Bắt buộc, kiểu số nguyên.
  • Mỗi service chỉ chấp nhận một số address_id cụ thể (liên hệ để được cung cấp).

order_number​

  • Bắt buộc, tối đa 50 ký tự.
  • Phải unique theo từng customer (không trùng mã đơn đã tạo trước đó).
  • Với service US_UPS_GROUND và US_UNIUNI_D: chỉ cho phép ký tự a-z A-Z 0-9 _ ( ) - , # space.

consignee_name​

  • Bắt buộc, tối đa 100 ký tự.
  • Với service US_UPS_GROUND: phải bao gồm họ và tên đầy đủ (ít nhất 2 từ cách nhau bởi khoảng trắng).

consignee_phone​

  • Không bắt buộc.
  • Nếu có, phải đúng 10 chữ số (ví dụ: 0123456789).

consignee_email​

  • Không bắt buộc.
  • Nếu có, phải đúng format email, tối đa 50 ký tự.

consignee_country​

  • Bắt buộc, mã quốc gia 2 ký tự (ISO-2).

consignee_state_code​

  • Bắt buộc khi consignee_country = US.
  • Không bắt buộc với các quốc gia khác.
  • Tối đa 50 ký tự.

consignee_postal_code​

  • Bắt buộc, tối đa 20 ký tự.
  • Format theo quốc gia:
    • US: 5 chữ số hoặc 5+4 (ví dụ: 57718 hoặc 57718-1234).
    • GB/UK: format Royal Mail (ví dụ: SW1A 1AA).
  • Với service US_UNIUNI và US_UNIUNI_D: postal code phải nằm trong danh sách vùng phục vụ của UniUni.

consignee_address​

  • Bắt buộc, tối đa 200 ký tự.

consignee_address_other​

  • Không bắt buộc, tối đa 200 ký tự.

unit_type​

  • Không bắt buộc. Mặc định: cm-g.
  • Giá trị cho phép: mm-g, cm-g, cm-kg, in-lb.

length / width / height​

  • Bắt buộc, giá trị số > 0.
  • Giới hạn tối đa: 150 cm (quy đổi theo unit_type).

weight​

  • Bắt buộc, giá trị số > 0.

product_name​

  • Không bắt buộc, tối đa 100 ký tự.

product_price​

  • Không bắt buộc, giá trị số ≥ 0.

service_add​

  • Không bắt buộc, tối đa 100 ký tự.

label_sender​

  • Không bắt buộc, tối đa 50 ký tự.
  • Nếu không set, lấy mặc định từ cài đặt label_sender của customer.

package_option (Lithium Battery)​

  • Không bắt buộc.
  • Chỉ được sử dụng với service: EPK, LBE, LBE6.
  • Giá trị theo service:
ServiceGiá trị cho phépMô tả
EPK, LBE818, 820818 = Marked, 820 = Unmarked
LBE68181, 8182, 8201, 8202Mã đầy đủ: 818x = Marked, 820x = Unmarked
  • Khi có package_option, các kiện hàng (packages) phải thỏa mãn giới hạn:
ServiceTrọng lượng tối đaLength + 2×Width + 2×Height
EPK≤ 11 lbs< 108 inch
LBE≤ 11 lbs< 108 inch
LBE6≤ 11 lbs< 108 inch
thông tin

Nếu hàng hoá có PIN package_option cần nhập mã phù hợp theo service.

và cần dán mark https://express.bellvn.com/UN-3091.jpg hoặc https://express.bellvn.com/UN-3481.jpg

Response

{
"error": false,
"ref": null,
"message": "Tạo đơn thành công",
"data": "DEV123456789",
"warnings": [],
"zone": "002"
}

Giải thích

STTTên trườngKiểu dữ liệuMô tả
1errorbooleanTrạng thái lỗi
2refStringMã tham chiếu giao dịch
3messageStringThông báo
4dataStringMã đơn hàng của BELL
5warningsArrayDanh sách cảnh báo khi hệ thống tự động chuyển ký tự sang ASCII (dịch vụ US_UNIUNI_D, US_UPS_GROUND, LBE6)
6zoneString/nullZone của tuyến vận chuyển. null nếu không xác định được zone
Zone

Response tạo đơn trả thêm trường zone ở cấp cao nhất. Trường này có kiểu String/null; giá trị được giữ nguyên dưới dạng chuỗi (ví dụ: "002"). Nếu không xác định được zone, giá trị là null. Trường zone không được trả trong response lỗi.

Mỗi phần tử trong warnings:

FieldMô tả
fieldTên trường bị chuyển đổi
labelTên hiển thị của trường
originalGiá trị gốc trước khi chuyển đổi
sanitizedGiá trị sau khi chuyển sang ASCII
messageMô tả hành động tự động

Tạo đơn hàng nâng cao (Advanced Mode)​

Dành cho các dịch vụ quốc tế yêu cầu khai báo chi tiết hàng hóa và hỗ trợ nhiều kiện hàng (multi-package).

MethodPOST
URL/api/order/create-order
Lưu ý

Các service sau bắt buộc phải sử dụng mode advanced:

  • UPS_WW_SAVER2, UPS_WW_SAVER
  • UPS_WW_EXPEDITED2, UPS_WW_EXPEDITED
  • UPS_WW_EXPRESS2, UPS_WW_EXPRESS
  • FEDEX_IPE2, FEDEX_IPE, FEDEX_IP2, FEDEX_IP
  • FEDEX_IE2, FEDEX_IE, FEDEX_ICP2, FEDEX_ICP
  • FEDEX_IP_SBP, FEDEX_IP_SBP2

Nếu sử dụng các service trên mà không truyền mode: "advanced" hoặc thiếu thông tin goods, hệ thống sẽ trả lỗi validation.

ASCII Auto-Sanitize

Với các dịch vụ US_UNIUNI_D, US_UPS_GROUND, LBE6: hệ thống tự động chuyển các ký tự tiếng Việt có dấu sang ASCII (ví dụ: á → a, đ → d) cho các trường tên/địa chỉ. Response sẽ kèm mảng warnings liệt kê các trường đã được tự động chuyển đổi.

Body request

{
"mode": "advanced",
"address_id": 0,
"service_code": "UPS_WW_EXPRESS",
"order_number": "PARTNER-ADV-001",
"order_code_upstream_partner": "UPSTREAM-001",
"consignee_name": "John Doe",
"consignee_company": "ACME Corp",
"consignee_phone": "2125550001",
"consignee_email": "john@example.com",
"consignee_country": "US",
"consignee_state_code": "NY",
"consignee_city": "New York",
"consignee_postal_code": "10001",
"consignee_address": "123 Main Street",
"consignee_address_other": "Suite 100",
"unit_type": "cm-g",
"package_option": null,
"label_sender": "MY STORE",
"service_add": "",
"packages": [
{
"weight": 1000,
"length": 30,
"width": 20,
"height": 15,
"goods": [
{
"name_en": "Electronic Device",
"name_vi": "Thiết bị điện tử",
"brand": "BrandName",
"packaging_type": "Box",
"origin": "CN",
"price": 150.00,
"quantity": 2,
"unit": "pcs",
"hs_code": "8471.30",
"material": "Plastic"
}
]
},
{
"weight": 500,
"length": 25,
"width": 18,
"height": 10,
"goods": [
{
"name_en": "Accessories",
"name_vi": "Phụ kiện",
"brand": null,
"packaging_type": null,
"origin": "VN",
"price": 25.50,
"quantity": 5,
"unit": "pcs",
"hs_code": null,
"material": null
}
]
}
],
"extra_fields": {
"trade_terms": "DDP",
"tax_type": "IOSS",
"tax_number": "IOSS-123456789",
"signature_required": true
}
}

So sánh Simple vs Advanced​

Đặc điểmSimple (mặc định)Advanced
Số kiện hàng1 kiện (truyền thẳng length, width, height, weight)Nhiều kiện (mảng packages)
Khai báo hàng hóaproduct_name + product_priceMảng goods chi tiết (tên, xuất xứ, HS code, ...)
Dịch vụ hỗ trợTất cả dịch vụ nội địaBắt buộc cho dịch vụ quốc tế (UPS WW, FedEx IP)
Extra fieldsKhôngHỗ trợ trade_terms, tax_type, tax_number

Giải thích các field bổ sung​

No.Field NameData TypeDescription
1modeStringBắt buộc với service nâng cao. Giá trị: "advanced"
2consignee_companyStringTên công ty người nhận. Bắt buộc với service advanced, tối đa 100 ký tự
3consignee_emailStringEmail người nhận. Không bắt buộc, tối đa 50 ký tự
4packagesArrayMảng các kiện hàng. Bắt buộc, tối thiểu 1 kiện
5packages[].weightDecimalTrọng lượng kiện (theo unit_type, mặc định gram)
6packages[].lengthDecimalChiều dài (theo unit_type, mặc định cm)
7packages[].widthDecimalChiều rộng (theo unit_type, mặc định cm)
8packages[].heightDecimalChiều cao (theo unit_type, mặc định cm)
9packages[].goodsArrayMảng hàng hóa trong kiện này. Bắt buộc, tối thiểu 1 mục
10packages[].goods[].name_enStringTên hàng hóa (tiếng Anh). Bắt buộc, tối đa 100 ký tự
11packages[].goods[].name_viStringTên hàng hóa (tiếng Việt). Không bắt buộc
12packages[].goods[].brandStringThương hiệu. Không bắt buộc
13packages[].goods[].packaging_typeStringLoại đóng gói. Không bắt buộc
14packages[].goods[].originStringMã quốc gia xuất xứ (ISO-2). Bắt buộc, 2 ký tự
15packages[].goods[].priceDecimalGiá trị hàng hóa (USD). Bắt buộc, tối thiểu 0.01
16packages[].goods[].quantityIntegerSố lượng. Bắt buộc, tối thiểu 1
17packages[].goods[].unitStringĐơn vị tính (vd: pcs, kg, set). Không bắt buộc
18packages[].goods[].hs_codeStringMã HS Code hải quan. Không bắt buộc
19packages[].goods[].materialStringChất liệu. Không bắt buộc
20extra_fieldsObjectThông tin thuế/thương mại bổ sung. Không bắt buộc
21extra_fields.trade_termsStringĐiều khoản thương mại: DDU, DDP, CIP, C&F. Với FEDEX_ICP/FEDEX_ICP2 chỉ được DDP
22extra_fields.tax_typeStringLoại thuế: IOSS, EORI, VAT
23extra_fields.tax_numberStringMã số thuế tương ứng (tối đa 100 ký tự)
24extra_fields.signature_requiredBooleanYêu cầu chữ ký khi giao hàng. Chỉ hỗ trợ dịch vụ JingDong, chỉ dùng trong Advanced Mode

Validation cho Advanced Mode​

packages​

  • Bắt buộc, mảng tối thiểu 1 phần tử.
  • Mỗi kiện phải có đầy đủ: weight, length, width, height.
  • Giá trị phải > 0. Kích thước tối đa 150cm (quy đổi theo unit_type).

goods (với service bắt buộc advanced)​

  • Bắt buộc, mảng tối thiểu 1 phần tử.
  • Mỗi mục hàng hóa phải có:
    • name_en: bắt buộc, tối đa 100 ký tự
    • origin: bắt buộc, 2 ký tự (mã quốc gia ISO-2)
    • price: bắt buộc, số > 0 (tối thiểu 0.01)
    • quantity: bắt buộc, số nguyên ≥ 1

extra_fields​

  • Không bắt buộc.
  • Nếu truyền, các giá trị bên trong đều là string hoặc boolean.

extra_fields.trade_terms

  • Giá trị cho phép: DDU, DDP, CIP, C&F.
  • Với dịch vụ FEDEX_ICP và FEDEX_ICP2: chỉ chấp nhận DDP.

extra_fields.tax_type

  • Giá trị cho phép: IOSS, EORI, VAT.

extra_fields.signature_required

  • Kiểu boolean. Chỉ hỗ trợ dịch vụ JingDong.
  • Chỉ có thể dùng trong Advanced Mode — bị từ chối (prohibited) nếu truyền ở Simple Mode.

Quy đổi đơn vị​

Hệ thống lưu trữ nội bộ theo mm-g. Khi truyền unit_type khác, hệ thống tự quy đổi:

unit_typeCân nặng → gramKích thước → mm
mm-g×1×1
cm-g×1×10
cm-kg×1000×10
in-lb×453.59×25.4

Response​

Giống response tạo đơn thường:

{
"error": false,
"ref": null,
"message": "Tạo đơn thành công",
"data": "BELL240625120345123"
}

Ví dụ lỗi validation​

{
"error": true,
"ref": null,
"message": "Service này yêu cầu mode \"advanced\" với đầy đủ thông tin goods.",
"errors": {
"goods.0.origin": ["origin là bắt buộc"],
"goods.0.price": ["price là bắt buộc"]
},
"data": null
}

Chỉnh sửa địa chỉ đơn lỗi và gửi lại​

Dùng cho đơn đang ở trạng thái Error (status = 11) do nhà vận chuyển từ chối vì thông tin địa chỉ người nhận. API lưu địa chỉ mới và đưa đơn vào luồng gửi lại, giữ nguyên mã đơn BELL — không tạo đơn mới.

Request là bất đồng bộ: BELL trả về 202 ngay sau khi lưu địa chỉ và xếp hàng, rồi mới gọi sang nhà vận chuyển. Kết quả cuối cùng lấy bằng cách tra cứu đơn (xem Theo dõi kết quả).

MethodPOST
URL/api/order/edit-order
Quy trình khuyến nghị
  1. Gọi /api/order/get-order-info/{order_number} để đọc status và processing_error — biết chính xác trường nào cần sửa.
  2. Gọi /api/order/edit-order với các field địa chỉ cần thay đổi.
  3. Nhận 202 = yêu cầu đã được xếp hàng. Tra lại /api/order/get-order-info/{order_number} để lấy kết quả cuối.
  4. Nếu bị lỗi, đọc code trong response lỗi để xử lý (xem bảng mã kết quả).

Body request

{
"order_code": "BELL240625120345123",
"consignee_country": "US",
"consignee_state_code": "CA",
"consignee_city": "San Francisco",
"consignee_postal_code": "94105",
"consignee_address": "123 Main Street",
"consignee_address_other": "Suite 200"
}

Giải thích

No.Field NameData TypeDescription
1order_codeStringBắt buộc. Mã vận đơn BELL (order_code), tối đa 100 ký tự. Không dùng mã đối tác hoặc mã nhà vận chuyển
2consignee_countryStringMã quốc gia (ISO-2), tối đa 2 ký tự
3consignee_state_codeStringState code, tối đa 50 ký tự. Bắt buộc với US và các dịch vụ advanced
4consignee_cityStringTỉnh / thành phố, tối đa 50 ký tự
5consignee_postal_codeStringMã bưu chính, tối đa 20 ký tự. Theo đúng quy tắc quốc gia / UniUni ở Validation Rules
6consignee_addressStringĐịa chỉ người nhận 1, tối đa 200 ký tự
7consignee_address_otherStringĐịa chỉ người nhận 2, tối đa 200 ký tự. Cho phép null để xoá

Quy tắc chỉnh sửa​

  • Phải truyền ít nhất một field địa chỉ. Chỉ truyền order_code sẽ bị từ chối VALIDATION_FAILED.
  • Field địa chỉ không truyền thì giữ nguyên giá trị đang lưu. Truyền lại đúng giá trị cũ vẫn được coi là yêu cầu gửi lại đơn.
  • Chỉ 6 field địa chỉ trên là được phép. Mọi key khác (address_id, service_code, status, consignee_name, consignee_phone, packages, goods, extra_fields, các field tiền...) đều bị từ chối, kể cả khi truyền null.
  • Kho gửi, mã đơn BELL, dịch vụ, kiện hàng và hàng hoá không thay đổi. Muốn sửa các thông tin này phải huỷ đơn và tạo lại.
  • Địa chỉ mới được validate theo đúng ràng buộc của dịch vụ đang gắn với đơn. consignee_country được tự chuẩn hoá sang chữ in hoa và UK → GB.
  • Với các dịch vụ yêu cầu ASCII (US_UNIUNI_D, US_UPS_GROUND, LBE6), địa chỉ gửi lên được tự chuyển sang ASCII và response trả về mảng warnings tương ứng.

Điều kiện đơn hợp lệ​

Đơn phải thoả tất cả điều kiện sau, nếu không sẽ nhận 409:

  • Thuộc đúng customer đang gọi API (sai chủ sở hữu trả 404, không phân biệt với đơn không tồn tại).
  • Đang ở trạng thái Error (status = 11), chưa bị xoá.
  • Chưa có mã đơn phía nhà vận chuyển và chưa có tracking.
  • Không có lượt gửi lại nào đang xử lý.
cảnh báo

Không import, sửa hay huỷ đơn từ giao diện trong lúc một lượt gửi lại đang chạy. Mỗi đơn chỉ xử lý một lượt tại một thời điểm.

Response thành công (202)

Envelope ngắn, giống API tạo đơn:

{
"error": false,
"ref": null,
"message": "Cập nhật đơn thành công",
"data": "BELL240625120345123",
"warnings": []
}

Giải thích

No.Field NameData TypeDescription
1errorbooleanfalse = BELL đã nhận và ghi nhận yêu cầu
2refStringLuôn null ở response thành công
3messageStringCập nhật đơn thành công
4dataStringMã vận đơn BELL (không đổi so với trước khi sửa)
5warningsArrayCảnh báo không chặn, ví dụ ASCII auto-sanitize. Cùng cấu trúc với API tạo đơn
202 không có nghĩa là nhà vận chuyển đã nhận đơn

202 chỉ khẳng định: địa chỉ mới đã được lưu và đơn đã được xếp vào luồng gửi lại. Việc gọi sang nhà vận chuyển diễn ra sau khi response đã trả về. Kết quả cuối cùng phải tra cứu riêng — xem mục Theo dõi kết quả.

Luồng xử lý​

Đồng bộ (trước khi trả response):

  1. Kiểm tra quyền sở hữu và điều kiện đơn.
  2. Validate địa chỉ mới theo ràng buộc của dịch vụ đang gắn với đơn.
  3. Xác thực địa chỉ qua nhà cung cấp xác thực (có thể mất tới ~25 giây).
  4. Tính cước tạm cho địa chỉ mới — chỉ đọc bảng giá, chưa ghi gì vào công nợ.
  5. Lưu địa chỉ mới + payload gửi nhà vận chuyển. Đơn chuyển từ Error (11) sang Init (1).
  6. Trả 202.

Bất đồng bộ (sau khi response đã trả về):

  1. BELL gọi nhà vận chuyển tạo lô hàng, ghi nhận kết quả.
  2. Nếu được tiếp nhận: cập nhật cước, tải nhãn, đơn về Label (3).
  3. Nếu bị từ chối: đơn quay lại Error (11), processing_error được cập nhật với lý do mới.

Theo dõi kết quả​

Gọi /api/order/get-order-info/{order_number} và đọc status:

statusÝ nghĩa
InitĐang gửi sang nhà vận chuyển. Chờ và tra lại
LabelGửi lại thành công. tracking_code và tracking_label_url đã có giá trị
ErrorNhà vận chuyển từ chối. Đọc processing_error để biết lý do, sửa tiếp rồi gọi lại API
mẹo

Thường mất vài giây tới vài chục giây. Nên chờ 5–10 giây rồi mới tra lần đầu, và giới hạn số lần poll. Nếu đơn ở Init quá lâu (trên vài phút), liên hệ hỗ trợ kèm mã đơn thay vì gọi lại API — gọi lại sẽ bị chặn 409.

Bảng mã kết quả​

Thành công luôn là 202 với envelope ngắn ở trên. Mọi mã dưới đây đều là lỗi xảy ra trước khi địa chỉ được lưu. Envelope lỗi có thêm field code — luôn xử lý theo code, không dựa vào message.

HTTPcodeÝ nghĩa và hành động phía đối tác
404ORDER_NOT_FOUNDKhông tìm thấy đơn hoặc đơn không thuộc customer. data = null
409ORDER_BUSYĐơn đang được xử lý bởi một tiến trình khác. Thử lại sau
409ORDER_NOT_EDITABLEĐơn không ở trạng thái Error, hoặc đã có mã đơn / tracking từ nhà vận chuyển
409RECOVERY_NOT_RETRYABLEKhông còn lượt khôi phục nào hợp lệ cho đơn này
409PROVIDER_RESULT_UNKNOWNĐã có một lượt gửi lại đang xử lý hoặc chưa rõ kết quả. Không gọi lại — chờ hoặc liên hệ hỗ trợ kèm ref
409BILLING_LOCKEDInvoice đã chốt hoặc công nợ cần kiểm tra. Liên hệ hỗ trợ
409ADDRESS_RECOMMENDATION_AVAILABLEĐịa chỉ có đề xuất chỉnh sửa. Xem suggestions, xác nhận rồi gọi lại
422VALIDATION_FAILEDPayload hoặc địa chỉ không hợp lệ. Xem errors
422ADDRESS_VALIDATION_FAILEDĐịa chỉ không xác thực được
422PRICING_UNAVAILABLEKhông tính được cước cho địa chỉ mới
422UNSUPPORTED_PROVIDERCấu hình nhà vận chuyển của đơn không hỗ trợ luồng này
503PROVIDER_UNAVAILABLEKhông chuẩn bị được yêu cầu gửi nhà vận chuyển. Chưa gửi gì đi, có thể thử lại
503ADDRESS_VALIDATION_UNAVAILABLEDịch vụ xác thực địa chỉ tạm thời không khả dụng. Thử lại sau
503LOCAL_PERSISTENCE_FAILEDBELL chưa xử lý được yêu cầu. Nếu response có ref khác null, không gọi lại — tra cứu trạng thái đơn trước

Ví dụ field không được phép sửa (422)

{
"error": true,
"ref": null,
"code": "VALIDATION_FAILED",
"message": "This field cannot be edited.",
"data": null,
"errors": {
"consignee_name": ["This field cannot be edited."]
},
"warnings": []
}

Ví dụ địa chỉ có đề xuất (409)

{
"error": true,
"ref": null,
"code": "ADDRESS_RECOMMENDATION_AVAILABLE",
"message": "Địa chỉ có đề xuất cần xác nhận trước khi tiếp tục.",
"data": null,
"suggestions": {
"consignee_city": "San Francisco",
"consignee_postal_code": "94105-1804"
},
"warnings": []
}

suggestions dùng tên field theo chuẩn đối tác và không được tự áp dụng — đối tác xác nhận rồi gọi lại API với giá trị mong muốn.

Cước phí và thanh toán​

  • Bước tính cước trong preflight chỉ đọc bảng giá và hạn mức ví. Không tạo giao dịch, không giữ tiền, không ghi cước.
  • Cước chỉ được cập nhật sau khi nhà vận chuyển tiếp nhận đơn, tức là sau khi response 202 đã trả về. Nhận 202 chưa có nghĩa là cước đã thay đổi.
  • Tra cước mới qua /api/price/get-price/{order_number} sau khi đơn về Label. Trước đó giá trị trả về vẫn là cước của địa chỉ cũ.
  • Nếu nhà vận chuyển từ chối, cước giữ nguyên như trước khi sửa.
  • Luồng này không tạo đơn mới, kiện hàng mới, hàng hoá mới hay giao dịch thanh toán mới.

Timeout và retry​

Không tự động gọi lại

API không còn chờ nhà vận chuyển, nhưng vẫn có bước xác thực địa chỉ đồng bộ có thể mất tới ~25 giây. Đặt timeout HTTP tối thiểu 60 giây.

Nếu request timeout hoặc lỗi mạng phía đối tác, không gọi lại ngay — địa chỉ có thể đã được lưu và đơn đã vào luồng gửi lại. Tra /api/order/get-order-info/{order_number} để xem status thực tế trước khi làm bất kỳ thao tác nào.

Tình huốngCó gọi lại được không
202 thành côngKhông. Đơn đã vào luồng gửi lại — hãy theo dõi kết quả
VALIDATION_FAILED, ADDRESS_VALIDATION_FAILEDĐược, sau khi sửa dữ liệu
ADDRESS_RECOMMENDATION_AVAILABLEĐược, sau khi xác nhận đề xuất
ORDER_BUSY, PROVIDER_UNAVAILABLE, ADDRESS_VALIDATION_UNAVAILABLEĐược, chờ ít phút rồi thử lại
PROVIDER_RESULT_UNKNOWN, LOCAL_PERSISTENCE_FAILED có refKhông. Tra cứu trạng thái đơn, liên hệ hỗ trợ kèm ref
Timeout / không nhận được responseKhông. Tra get-order-info trước
Đơn về Error với processing_error mớiĐược, sửa địa chỉ theo lý do rồi gọi lại

Hủy đơn hàng​

MethodPOST
URL/api/order/cancel-order

Payload request

No.Field NameData TypeDescription
1order_numberStringMã vận đơn của BELL

Response

{
"error": false,
"ref": null,
"message": "Thành công",
"data": null
}

In nhãn vận đơn​

MethodGET
URL/api/order/print-order/{order_number}

Path parameter

No.Field NameData TypeDescription
1order_numberStringMã vận đơn BELL hoặc mã đơn đối tác (order_code_partner)

Response

{
"error": false,
"ref": null,
"message": "Thành công",
"data": {
"orderNumber": "BELL1202103548",
"tracking": "42080521921449037400250000264",
"labelFormat": "PDF",
"labelSize": "4x6",
"label": "",
"labelUrl": "https://storage.bellvn.com/labels/BELL1202103548.pdf",
"receiptUrls": [
"https://storage.bellvn.com/receipts/BELL1202103548_1.pdf"
],
"trackings": [
{
"tracking_code": "42080521921449037400250000264",
"package_no": 1
}
],
"processing_error": null
}
}

Giải thích

No.Field NameData TypeDescription
1errorbooleanTrạng thái lỗi
2refStringMã tham chiếu
3messageStringThông báo
4data.orderNumberStringMã đơn hàng truy vấn
5data.trackingStringTracking number chính của đơn
6data.labelFormatStringĐịnh dạng file nhãn: PDF, GIF, PNG, JPG (hoặc rỗng nếu chưa có nhãn)
7data.labelSizeStringKích thước nhãn (mặc định 4x6)
8data.labelStringNội dung nhãn Base64 (hiện luôn rỗng — dùng labelUrl thay thế)
9data.labelUrlStringURL file nhãn vận đơn để tải/xem trực tuyến
10data.receiptUrlsArrayDanh sách URL file biên lai (waybill receipt). Có thể rỗng []
11data.trackingsArrayDanh sách tracking theo từng kiện (multi-package). Rỗng [] nếu đơn 1 kiện hoặc chưa có tracking
12data.processing_errorStringLý do đơn bị lỗi (status = 11 Error) đã được diễn giải sang tiếng Việt. null nếu đơn không ở trạng thái lỗi
thông tin

receiptUrls và trackings chỉ có giá trị với các đơn hàng dịch vụ JingDong (đơn nhiều kiện hoặc có biên lai riêng). Với các dịch vụ khác, hai trường này trả về mảng rỗng.


Tra cứu thông tin đơn hàng​

MethodGET
URL/api/order/get-order-info/{order_number}

Path parameter

No.Field NameData TypeDescription
1order_numberStringMã đơn hàng BELL (order_code), mã đối tác (order_code_partner), hoặc ID nội bộ (id)

Response

{
"status": "success",
"message": "Get order info successfully",
"data": {
"order_code": "BELL240625120345123",
"order_code_partner": "DEV123456789",
"zone": "002",
"status": "Label",
"service": "EPK",
"reason": null,
"processing_error": null,
"tracking_code": "42080521921449037400250000264",
"tracking_label_url": "https://storage.bellvn.com/labels/BELL240625120345123.pdf",
"carrier": "USPS",
"ship_date": "2024-06-25",
"consignee_name": "sarenda mcguire",
"consignee_phone": "0123456789",
"consignee_company": null,
"consignee_country": "US",
"consignee_state": "SD",
"consignee_city": "Wildomar",
"consignee_postal_code": "57718",
"consignee_address": "6105 W Elmwood Dr",
"consignee_address2": null,
"created_date": "2024-06-25 12:03:45"
}
}

Giải thích response

No.Field NameData TypeDescription
1statusStringsuccess hoặc error
2messageStringThông báo kết quả
3data.order_codeStringMã vận đơn BELL
4data.order_code_partnerStringMã đơn hàng của đối tác
5data.zoneString/nullZone của tuyến vận chuyển. null nếu không xác định được zone
6data.statusStringTrạng thái đơn hàng (xem bảng bên dưới)
7data.serviceStringMã dịch vụ
8data.reasonStringLý do (ví dụ: lý do hủy đơn). Null nếu không có
9data.processing_errorStringLý do đơn bị lỗi (status = Error), đã được BELL diễn giải sang tiếng Việt. null nếu đơn không ở trạng thái lỗi hoặc không xác định được nguyên nhân
10data.tracking_codeStringTracking number của carrier
11data.tracking_label_urlStringURL file nhãn vận đơn
12data.carrierStringTên carrier vận chuyển
13data.ship_dateStringNgày gửi hàng
14data.consignee_nameStringTên người nhận
15data.consignee_phoneStringSố điện thoại người nhận
16data.consignee_companyStringCông ty người nhận
17data.consignee_countryStringMã quốc gia (ISO-2)
18data.consignee_stateStringBang / tỉnh
19data.consignee_cityStringThành phố
20data.consignee_postal_codeStringMã bưu chính
21data.consignee_addressStringĐịa chỉ người nhận
22data.consignee_address2StringĐịa chỉ người nhận 2
23data.created_dateStringThời gian tạo đơn

Bảng trạng thái đơn hàng

Giá trịMô tả
InitMới tạo
LabelĐã có nhãn
In TransitĐang vận chuyển
Out For DeliveryĐang giao hàng
DeliveredĐã giao thành công
ExceptionCó vấn đề phát sinh
VoidĐã hủy
Request CancelYêu cầu hủy
UnknownKhông xác định
DraftBản nháp

Lỗi thường gặp

{
"status": "error",
"message": "Order not found"
}
{
"status": "error",
"message": "Order not belong to Customer"
}

Track shipment​

Nhận hành trình tự động

Để BELL chủ động gửi cập nhật tới hệ thống của Quý khách, xem Webhook hành trình đơn. API GET bên dưới dùng để tra cứu, đồng bộ lịch sử ban đầu hoặc đối chiếu khi cần.

MethodGET
URL/api/order/tracking/{order_number}

Path request

No.Field NameData TypeDescription
1order_numberStringMã vận đơn của BELL

Response

{
"error": false,
"ref": null,
"message": "Thành công",
"data": [
{
"trackingNumber": "BELL2512171654532484",
"code": "12345678900",
"city": "City 0",
"stateCode": "State 0",
"zipCode": "Zip 0",
"countryCode": "Country 0",
"eventDate": "2025-12-18T03:57:04.896549Z",
"eventStatus": "LabelCreated 0",
"note": "Label Created"
},
{
"trackingNumber": "BELL2512171654532484",
"code": "12345678901",
"city": "City 1",
"stateCode": "State 1",
"zipCode": "Zip 1",
"countryCode": "Country 1",
"eventDate": "2025-12-18T03:57:04.896558Z",
"eventStatus": "LabelCreated 1",
"note": "Label Created"
}
]
}

Giải thích

No.Field NameData TypeDescription
1errorbooleanTrạng thái lỗi (false = thành công)
2refStringMã tham chiếu yêu cầu (có thể null)
3messageStringThông báo kết quả xử lý
4dataArrayDanh sách sự kiện tracking
5data[].trackingNumberStringMã vận đơn / tracking number
6data[].codeStringMã sự kiện hoặc mã tham chiếu nội bộ
7data[].cityStringThành phố phát sinh sự kiện
8data[].stateCodeStringMã bang / tỉnh
9data[].zipCodeStringMã bưu chính
10data[].countryCodeStringMã quốc gia (ISO-2)
11data[].eventDateStringThời gian xảy ra sự kiện (ISO 8601, UTC)
12data[].eventStatusStringTrạng thái / nội dung sự kiện tracking
13data[].noteStringGhi chú/mô tả trạng thái

Báo giá vận chuyển​

MethodPOST
URL/api/price/get-price

Yêu cầu header Authorization: Bearer <token> theo hướng dẫn xác thực. API báo giá một dịch vụ, một kiện hàng trước khi tạo đơn. Không cần order_number, không tạo đơn hoặc nhãn, không kiểm tra ví/công nợ và không phát sinh thanh toán.

Thay đổi contract

Đối tác phải truyền một service_code được hỗ trợ và một address_id dương, tồn tại trong hệ thống. Không dùng kho 0 để tự chọn kho.

API không còn trả danh sách toàn bộ dịch vụ hoặc tự chọn giá rẻ nhất. data chỉ chứa một báo giá, không còn field carrier. Đối tác cần cập nhật payload và logic đọc response nếu đang tích hợp contract cũ.

Body request​

{
"address_id": 57,
"service_code": "US_UNIUNI_D",
"consignee_country": "US",
"consignee_state_code": "CA",
"consignee_city": "Los Angeles",
"consignee_postal_code": "90001",
"consignee_address": "123 Example Street",
"unit_type": "cm-g",
"weight": 300,
"length": 20,
"width": 10,
"height": 5
}

Kho và địa chỉ trong ví dụ chỉ minh họa; cần chọn kho thực tế phù hợp với dịch vụ đã được mở cho tài khoản.

FieldKiểu dữ liệuBắt buộcQuy tắc
address_idIntegerCóSố nguyên ≥ 1, kho phải tồn tại và được hỗ trợ bởi dịch vụ. Xem bảng bên dưới
service_codeStringCóChỉ nhận EPK, LBE6, US_UNIUNI_D, US_UPS_GROUND
consignee_countryStringCóCả bốn dịch vụ hiện chỉ hỗ trợ US; hệ thống chuẩn hóa mã quốc gia sang chữ hoa
consignee_state_codeStringCóMã bang, tối đa 50 ký tự
consignee_cityStringCóThành phố, tối đa 50 ký tự
consignee_postal_codeStringCóTối đa 20 ký tự; 5 chữ số hoặc ZIP+4, ví dụ 90001 hoặc 90001-1234. Với US_UNIUNI_D, 5 chữ số đầu phải thuộc vùng phục vụ UniUni
consignee_addressStringCóĐịa chỉ người nhận, tối đa 200 ký tự
consignee_address_otherString/nullKhôngĐịa chỉ bổ sung, tối đa 200 ký tự
consignee_companyString/nullKhôngTên công ty, tối đa 100 ký tự
consignee_emailString/nullKhôngEmail hợp lệ, tối đa 50 ký tự
weightNumberCóCân thực; số hữu hạn ≥ 0.01, theo unit_type
length, width, heightNumberCóMỗi chiều là số hữu hạn ≥ 0.01, không vượt 150 cm sau quy đổi
unit_typeString/nullKhôngmm-g, cm-g, cm-kg, in-lb; mặc định cm-g khi bỏ qua hoặc gửi null
package_optionString/nullKhôngMã pin lithium; chỉ áp dụng cho EPK và LBE6 trong API báo giá
modeString/nullKhôngBỏ qua, null hoặc simple; không hỗ trợ advanced

Dịch vụ và kho gửi

Dịch vụaddress_id được hỗ trợ
EPKKhông có danh sách giới hạn riêng; kho phải tồn tại và có cấu hình quốc gia gửi
LBE673, 75, 80, 101, 113
US_UNIUNI_D57, 58, 100
US_UPS_GROUND73, 75, 80, 101, 113, 967

Lấy ID kho từ data[].shop_id của GET /api/order/list-shop (xem Danh sách kho hàng). Kho vẫn phải tồn tại trong môi trường đang gọi. Tài khoản phải được BELL gán bảng giá bán đang hoạt động cho đúng dịch vụ; bảng giá public chưa được gán không cấp quyền báo giá.

Phạm vi dữ liệu
  • Chỉ gửi một kiện bằng weight, length, width, height ở cấp cao nhất. mode=advanced, is_advanced=true hoặc packages có dữ liệu đều trả 422. Nên bỏ hoàn toàn packages và is_advanced khỏi payload báo giá.
  • US_UNIUNI_ID và các mã ngoài bốn dịch vụ trên không được hỗ trợ.
  • Không yêu cầu hoặc sử dụng consignee_name, consignee_phone; nếu đối tác cũ vẫn gửi thì hai field này bị bỏ qua. Quy tắc tạo đơn hàng không thay đổi.
  • Các field tạo đơn như order_number, goods, product_price, label_sender, service_add không tham gia tính báo giá.
  • Với LBE6, US_UNIUNI_D, US_UPS_GROUND, hệ thống tự chuẩn hóa company, state, city và các dòng địa chỉ sang ASCII trước validation.

Đơn vị và hàng có pin​

unit_typeKích thướcCân nặng
mm-gmmgram
cm-gcmgram
cm-kgcmkg
in-lbinchpound

Hệ thống quy đổi về cm và gram: 1 mm = 0.1 cm, 1 kg = 1000 gram, 1 inch = 2.54 cm, 1 pound = 453.59237 gram. Không làm tròn cân hoặc kích thước trung gian.

Nếu hàng có pin, gửi package_option dạng chuỗi theo dịch vụ:

Dịch vụpackage_option hợp lệ
EPK818, 820
LBE68181, 8182, 8201, 8202
  • US_UNIUNI_D và US_UPS_GROUND không hỗ trợ tùy chọn pin trong API này.
  • Khi có package_option: cân thực sau quy đổi phải ≤ 11 lbs và length + 2 × width + 2 × height phải < 108 inch.
  • Với LBE6, mã bắt đầu bằng 818 được gửi tới UBI dưới dạng Battery Only, mã bắt đầu bằng 820 là Inside Equipment. Đối tác chỉ gửi package_option, không gửi batteryPacking riêng.
  • Không có pin thì bỏ qua hoặc gửi null. API không tính thêm riêng phí pin, chữ ký, bảo hiểm hoặc dịch vụ gia tăng.

Cách xác định báo giá​

  • EPK: cân tính cước là giá trị lớn hơn giữa cân thực và cân thể tích (length_cm × width_cm × height_cm / hệ số quy đổi của dịch vụ × 1000, đơn vị gram). API lấy giá của bậc cân phù hợp trong bảng giá bán, không nhân thêm cân và không gọi UBI.
  • LBE6 / US_UNIUNI_D / US_UPS_GROUND: dùng cân thực để tra cấu hình bảng giá, lấy dự phí từ UBI cho đúng kho và số đo kiện rồi áp dụng tỷ lệ điều chỉnh giá bán đã cấu hình.
  • Tiền được làm tròn tới hai chữ số thập phân ở bước cuối. API không chuyển đổi ngoại tệ; amount theo tiền tệ cấu hình của dịch vụ. Response không có field currency; liên hệ BELL để xác nhận tiền tệ khi tích hợp.
  • Báo giá UBI là dự phí, không phải phí quyết toán cuối của nhà vận chuyển. Muốn tra cước của đơn đã tạo, dùng API tra cứu cước phí đơn hàng.
  • Không có giá phù hợp thì trả lỗi; không tự chọn bậc gần nhất, giá rẻ nhất hoặc trả thành công giả với giá 0. Giá thực sự bằng 0 trong cấu hình vẫn hợp lệ.

Response thành công​

{
"error": false,
"ref": null,
"message": "Thành công",
"data": [
{
"serviceCode": "US_UNIUNI_D",
"serviceName": "Tên dịch vụ theo cấu hình",
"amount": 2.87,
"addressId": 57,
"postcode": "92843"
}
]
}
FieldKiểu dữ liệuMô tả
errorBooleanfalse khi báo giá thành công
refnullKhông có mã tham chiếu trong response báo giá
messageStringThông báo kết quả
dataArrayĐúng một báo giá, chỉ gồm năm field bên dưới
data[].serviceCodeStringMã dịch vụ được yêu cầu
data[].serviceNameString/nullTên dịch vụ theo cấu hình
data[].amountNumberGiá bán sau làm tròn, không phải chuỗi; không đảm bảo giữ đuôi .00
data[].addressIdIntegerID kho gửi đã chọn
data[].postcodeStringMã bưu chính của kho gửi, không phải consignee_postal_code; chuỗi rỗng nếu kho chưa có mã bưu chính

Tên dịch vụ, giá và mã bưu chính trong ví dụ chỉ minh họa. Response không trả carrier, giá mua hoặc dữ liệu thô từ nhà vận chuyển.

Mã lỗi báo giá​

HTTPcodeNguyên nhân / cách xử lý
401Không có code chuẩn của báo giáToken thiếu, sai hoặc hết hạn; kiểm tra lại xác thực
422VALIDATION_FAILEDPayload, kho, mode, địa chỉ, số đo hoặc tùy chọn pin không hợp lệ; sửa các field trong errors
422UNSUPPORTED_PRICE_SERVICEMã dịch vụ ngoài bốn mã được hỗ trợ; sửa service_code
403SERVICE_NOT_ENABLEDTài khoản chưa được gán bảng giá bán đang hoạt động cho dịch vụ; liên hệ BELL
404PRICE_NOT_FOUNDKhông có vùng giá hoặc bậc cân phù hợp
503PRICE_CONFIGURATION_INVALIDCấu hình báo giá thiếu, trùng hoặc không hợp lệ; liên hệ BELL
502PROVIDER_RATE_UNAVAILABLEKhông lấy được dự phí hợp lệ từ UBI; có thể thử lại sau

Ví dụ lỗi validation (422)

{
"error": true,
"ref": null,
"message": "Báo giá chỉ hỗ trợ simple mode, một kiện.",
"data": [],
"code": "VALIDATION_FAILED",
"errors": {
"mode": ["Báo giá chỉ hỗ trợ simple mode, một kiện."]
}
}

Ví dụ chưa được mở dịch vụ (403)

{
"error": true,
"ref": null,
"message": "Customer chưa được mở dịch vụ báo giá này.",
"data": [],
"code": "SERVICE_NOT_ENABLED"
}

Lỗi báo giá trả data: []; lỗi validation có thêm errors theo field. Riêng lỗi token bị chặn trước bước báo giá trả định dạng xác thực {"status":"error","message":"..."}, không theo envelope trên.


Tra cứu cước phí đơn hàng​

API này tra cước đã ghi nhận của đơn hàng, khác với API báo giá trước khi tạo đơn. Contract của endpoint GET không thay đổi.

MethodGET
URL/api/price/get-price/{order_number}

Path request

No.Field NameData TypeDescription
1order_numberStringMã vận đơn của BELL

Response

{
"error": false,
"message": "Success",
"data": [
{
"order_code": "BELL2512171654532484",
"amount": 15.50,
"type": "MAIN"
}
]
}

Giải thích

No.Field NameData TypeDescription
1errorbooleanTrạng thái lỗi (false = thành công)
2messageStringThông báo kết quả xử lý
3dataArrayDanh sách chi tiết cước phí
4data[].order_codeStringMã vận đơn
5data[].amountDecimalSố tiền cước
6data[].typeStringLoại phí (MAIN: cước chính, hoặc phụ phí khác)
thông tin

API chỉ trả về cước phí của các đơn hàng thuộc invoice đang active. Nếu đơn chưa được tính cước hoặc chưa có invoice, sẽ trả về lỗi.