Tracking API
当你只需要向客户展示一票货件的当前状态时,调用匿名 Tracking API。请求参数只能是 tracking_number,不能用 package code、scan code 或内部 ID 替代。
调用接口
| 方法 | 路径 | 用途 |
|---|---|---|
GET | /public/tracking/{tracking_number}/ | 读取 JSON 状态投影。 |
HEAD | /public/tracking/{tracking_number}/ | 只检查状态码和响应头,不读取 body。 |
完整 URL 是 https://mexpress.nz/api/v1/public/tracking/{tracking_number}/。请将 tracking number 编码为一个 path segment。
HEAD 与 GET 共享成功、未找到和限流状态,但 HEAD 不返回响应体。
读取 200 响应
200 OK 始终返回下列 required keys。timeline 可以是空数组;milestone、reason 和时间字段按契约可以为 null。
{
"tracking_number": "MX123456789",
"status": "out_for_delivery",
"milestone": "out_for_delivery",
"reason": null,
"status_label": "Out for delivery",
"package_count": 2,
"package_summary": {
"total": 2,
"created": 0,
"picked_up": 0,
"in_warehouse": 0,
"out_for_delivery": 2,
"exception": 0,
"returning": 0,
"delivered": 0,
"returned": 0,
"cancelled": 0,
"unresolved": 0
},
"projection_revision": 7,
"occurred_at": "2026-07-02T03:04:05.000000Z",
"timeline": []
}| 字段 | 契约 |
|---|---|
tracking_number | required string;请求的 shipment 标识。 |
status | required enum:created、in_transit、out_for_delivery、exception、delivered、returned、cancelled、completed。 |
milestone | nullable enum:information_received、picked_up、at_transit_facility、out_for_delivery、delivery_exception、returning_to_sender、delivered、returned_to_sender、cancelled、delivered_and_returned、partially_delivered、partially_returned。 |
reason | nullable enum:recipient_unavailable、address_issue、access_issue、recipient_refused、damaged、other_delivery_issue。 |
status_label | required string;用于客户界面展示。 |
package_count | required、非负 integer。 |
projection_revision | required、非负 integer;可用于缓存比较。 |
occurred_at | nullable RFC 3339 date-time string;当前投影时间。 |
package_summary | required object;固定 11 个键,每个值为非负 integer。 |
timeline | required array;可为空,事件按 oldest-first 排列。 |
package_summary 的固定键和顺序是:total、created、picked_up、in_warehouse、out_for_delivery、exception、returning、delivered、returned、cancelled、unresolved。不要添加键,也不要从计数推断具体 package 身份。
每个 timeline item 都有 required status、label 和 nullable occurred_at。status 只能是 created、picked_up、in_warehouse、loaded、out_for_delivery、delivery_attempted、delivered、exception、return_initiated、returned_to_sender、cancelled、completed;label 是 string,occurred_at 是 nullable date-time。空数组表示没有可用 timeline event。事件按 oldest-first 返回。
导入可运行示例
下面的两个 region 是唯一示例源。它们明确处理 200、detail-only 404、429 和正整数 Retry-After,不把 token 或追踪数据放进浏览器 credential flow。
export async function fetchTracking(
trackingNumber,
{ baseUrl = API_BASE_URL, fetchImpl = globalThis.fetch } = {},
) {
const response = await fetchImpl(
endpoint(baseUrl, `/public/tracking/${encodeURIComponent(trackingNumber)}/`),
{
method: "GET",
headers: { Accept: "application/json" },
},
);
if (response.status === 200) return { kind: "ok", data: await json(response) };
if (response.status === 404) return { kind: "not_found" };
if (response.status === 429) {
const retryAfter = Number.parseInt(header(response.headers, "Retry-After") ?? "", 10);
if (!Number.isInteger(retryAfter) || retryAfter < 1) {
throw new Error("Tracking 429 did not include a positive Retry-After.");
}
return { kind: "rate_limited", retryAfter, error: await json(response) };
}
throw new Error(`Tracking request failed with HTTP ${response.status}.`);
}def fetch_tracking(tracking_number: str, *, client, base_url: str = API_BASE_URL):
response = client.get(
_url(base_url, f"/public/tracking/{quote(tracking_number, safe='')}/"),
headers={"Accept": "application/json"},
)
if response.status_code == 200:
return {"kind": "ok", "data": response.json()}
if response.status_code == 404:
return {"kind": "not_found"}
if response.status_code == 429:
raw_retry_after = _header(response, "Retry-After")
try:
retry_after = int(raw_retry_after or "")
except ValueError as error:
raise ValueError("Tracking 429 did not include a positive Retry-After.") from error
if retry_after < 1:
raise ValueError("Tracking 429 did not include a positive Retry-After.")
return {"kind": "rate_limited", "retry_after": retry_after, "error": response.json()}
raise RuntimeError(f"Tracking request failed with HTTP {response.status_code}.")处理错误和轮询
404 只有 detail-only 结果。对未知、隐藏、格式错误或其他不可用原因都显示同一个中性结果,不向客户泄露区别。
429 的 JSON body 是 detail: "Too many public tracking requests. Retry after the indicated delay." 与 code: "public_tracking_rate_limited",并带正整数 Retry-After header。至少等待该时长,再使用指数退避和随机 jitter。
匿名限额是每个 source IP 每秒 5 次、burst 30 次,另有共享服务限额。只在客户界面需要刷新时轮询;单个 tracking number 每分钟一次是保守默认值。后端需要持续更新时优先使用 Webhooks。
公开投影不会包含收件人联系方式或地址、package scan code、POD media、精确设备位置、driver identity、计费、raw scan evidence 或内部 audit/risk 字段。
验收
- [ ]
GET只展示本页列出的安全字段。 - [ ] 只在不需要 body 时使用
HEAD。 - [ ]
404在客户界面中只有一个中性结果。 - [ ]
429遵守正整数Retry-After,再执行退避与 jitter。 - [ ] 轮询没有 tight loop,并在合适时改用 Webhooks。