# awice-openapi-sdk **Repository Path**: baige95/awice-openapi-sdk ## Basic Information - **Project Name**: awice-openapi-sdk - **Description**: 国际物流运价 API 官方 SDK(PHP / Python):海运整柜/拼箱、空运、国际快递、FBA 头程运价查询,单文件零依赖。GitHub 镜像。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-09-17 - **Last Updated**: 2026-10-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 物流巴巴开放平台 SDK [English](./README.en.md) | 简体中文 > 代码同时托管在 [GitHub](https://github.com/HJP957547207/awice-openapi-sdk)(主仓库)和 [Gitee](https://gitee.com/baige95/awice-openapi-sdk)(国内镜像),两边内容保持同步。国内访问 GitHub 不畅时用 Gitee 即可。 国际物流运价查询 API 的官方 SDK。**海运整柜(FCL)、海运拼箱(LCL)、国际空运、国际快递、FBA 头程**五类实时运价、船期查询与四类物流下单,外加港口、机场、船公司、航空公司、国家五类基础数据字典,一次对接接进你自己的 TMS、ERP 或官网询价页。 - 官网: - 文档: - 控制台: ## 特点 - **单文件、零依赖**。PHP 版只要 curl 扩展(PHP 7.1+),Python 版只用标准库(Python 3.7+),Java 版使用 JDK 标准库(JDK 11+,兼容 17、21)。复制一个文件进项目就能用,不需要 composer、pip 或 Maven 依赖。 - **签名自动处理**。HMAC-SHA256 签名里最容易错的几处(PATH 不含 `/api` 前缀、body 要用同一个 JSON 串算 MD5)已经封装好。 - **限流自动退避**。撞到 QPS 上限时按服务端返回的 `Retry-After` 自动重试,批量跑数据不用自己写重试循环。 - **错误提示说人话**。比如「积分不足」会直接告诉你去控制台哪里领免费额度,而不是让你对着一个错误码发呆。 ## 快速开始 先到[控制台](https://www.5688.cn/user/openapi/apps)创建应用拿到 AppKey / AppSecret。需要积分的查价接口可先领取免费体验包;ping 和下单接口不要求积分余额,下单须完成客户实名认证。 ### PHP ```php require 'AwiceClient.php'; $client = new \Awice\OpenApi\AwiceClient('你的AppKey', '你的AppSecret'); // 先验证签名通了(ping 不消耗积分) $client->ping(); // 查上海到洛杉矶的整柜运价 $res = $client->fcl([ 'pol' => 'CNSHA', // 起运港:UN/LOCODE、中文名、英文名都认 'pod' => '洛杉矶', // 目的港 'limit' => 10, ]); foreach ($res['list'] as $rate) { $p = $rate['prices']; echo "{$rate['carrier']['name']} 20GP: {$p['20GP']} 40HQ: {$p['40HQ']} {$p['currency']}" . " 航程 {$rate['transit']['days']} 天 有效期至 {$rate['valid_until']}\n"; } ``` ### Python ```python from awice_client import AwiceClient client = AwiceClient("你的AppKey", "你的AppSecret") client.ping() res = client.fcl(pol="CNSHA", pod="洛杉矶", limit=10) for rate in res["list"]: p = rate["prices"] print(rate["carrier"]["name"], p["20GP"], p["40HQ"], p["currency"], f'航程 {rate["transit"]["days"]} 天', rate["valid_until"]) ``` ### Java(JDK 11+) 复制 [java/AwiceClient.java](./java/AwiceClient.java),无需第三方依赖。 ```java AwiceClient client = new AwiceClient(key, secret); AwiceClient.ApiResponse res = client.fcl( java.util.Map.of("pol", "CNSHA", "pod", "USLAX", "limit", 10)); System.out.println(AwiceClient.Json.stringify(res.getData())); ``` [Java 运行示例、版本与异常说明](./java/README.md)。Java 返回 `ApiResponse`(保留完整响应);PHP/Python 单文件客户端直接返回 `data`。 ## 返回长什么样 PHP/Python 单文件客户端的 `fcl()` 直接返回 `data`,Java 使用 `fcl(...).getData()` 获取同一结构(真实响应,非杜撰): ```json { "resolved": { "pol": { "input": "CNSHA", "code": "CNSHA", "name": "上海", "name_en": "shanghai" }, "pod": { "input": "洛杉矶", "code": "USLSA", "name": "洛杉矶", "name_en": "los angeles,ca" } }, "total": 128, "page": 1, "limit": 10, "list": [ { "id": "54698", "pol": { "code": "CNSHA", "name": "上海", "name_en": "shanghai" }, "pod": { "code": "USLSA", "name": "洛杉矶", "name_en": "los angeles,ca" }, "carrier": { "code": "CMA", "name": "达飞轮船" }, "transit": { "is_direct": true, "days": 16, "port": "", "port_en": "" }, "schedule": { "cutoff_date": "", "departure_date": "", "arrival_date": "", "vessel_name": "", "voyage": "", "service_code": "", "is_real": false }, "prices": { "20GP": 1880, "40GP": 2110, "40HQ": 2110, "currency": "USD" }, "surcharges": [], "valid_until": "2026-12-31" } ] } ``` `resolved` 会回显你传的原值和解析结果——传中文名时用它确认系统认成了哪个港口。 `schedule.is_real` 为 `true` 表示是船公司真实船期,`false` 表示该条报价未关联具体航次。 ## 可用接口 可用接口如下——**没有的不会写在这里**。 | 方法 | 接口 | 说明 | |---|---|---| | `fcl()` | `POST /openapi/v1/freight/fcl/search` | 海运整柜运价 | | `lcl()` | `POST /openapi/v1/freight/lcl/search` | 海运拼箱运价 | | `air()` | `POST /openapi/v1/freight/air/search` | 国际空运运价 | | `express()` | `POST /openapi/v1/freight/express/search` | 国际快递 / 专线运价 | | `fba()` | `POST /openapi/v1/freight/fba/search` | FBA 头程运价 | | `schedule()` | `POST /openapi/v1/schedule/search` | 船期查询(港口对、船公司、ETD 日期范围) | | `schedule_detail()` / `scheduleDetail()` | `POST /openapi/v1/schedule/detail` | 同一应用的航次标识获取详情 | | `ports()` | `GET /openapi/v1/dict/port` | 港口字典 | | `airports()` | `GET /openapi/v1/dict/airport` | 机场字典 | | `carriers()` | `GET /openapi/v1/dict/carrier` | 船公司字典 | | `airlines()` | `GET /openapi/v1/dict/airline` | 航空公司字典 | | `countries()` | `GET /openapi/v1/dict/country` | 国家字典 | | `popular()` | `GET /openapi/v1/dict/popular` | 常用数据集(做下拉框用) | | `ping()` | `ANY /openapi/v1/ping` | 连通性自检,不计费 | > 目前**没有**舱位、货物轨迹和账单接口;四类下单与本人订单详情见下文。有这类需求可以到官网留言,会作为排期参考。 ## 港口怎么传 `pol` / `pod` 三种写法都认,按可靠性排序: 1. **UN/LOCODE**(推荐):`CNSHA`、`USLAX`、`MYPKG` 2. **中文名**:`上海`、`钦州港`、`勒阿弗尔` 3. **英文名**:`shanghai`、`port klang` 同名港口会返回 `1002`,比如「奥克兰」美国(`USOAK`)和新西兰(`NZAUC`)都有。两种解法: ```php // 方法一:加国家码消歧 $client->fcl(['pol' => 'CNSHA', 'pod' => '奥克兰', 'pod_country' => 'US']); // 方法二:先查字典拿准确代码 $ports = $client->ports(['keyword' => '奥克兰']); ``` SDK 会把候选放在异常的 `candidates` 属性里,可以直接拿来让用户选。 ## 两个最容易踩的坑 如果你不用这个 SDK 而是自己实现签名,这两点务必注意: **1. 签名的 PATH 不含 `/api` 前缀** ``` 请求 URL: https://www.5688.cn/api/openapi/v1/freight/fcl/search 签名 PATH: /openapi/v1/freight/fcl/search ``` 也不含 query string。这是 `2002 签名校验失败` 最常见的原因。 **2. body 要用同一个 JSON 字符串算 MD5 和发送** 签名时序列化一次、发送时再序列化一次,只要字段顺序或空格有任何差异,服务端算出的 `MD5(BODY)` 就对不上。 ## 错误码 | 码 | 含义 | 怎么办 | |---|---|---| | `0` | 成功 | — | | `1001` | 参数无效 / 港口名无法识别 | 先用 `ports()` 查正确代码 | | `1002` | 名称有歧义 | 加 `pol_country` / `pod_country`,或用代码 | | `2002` | 签名校验失败 | 见上面「两个坑」 | | `2003` | 时间戳超出 ±300 秒 | 检查服务器时间是否与 NTP 同步 | | `2004` | Nonce 重复 | 同一随机串 10 分钟内只能用一次 | | `2005` | IP 不在白名单 | 控制台添加当前出口 IP | | `3001` | 积分不足 | 没领过就去控制台领免费体验包 | | `3003` | 无有效订阅 | 同上 | | `3004` | 套餐已到期 | 续费 | | `4001` | QPS 超限 | SDK 会自动退避重试;仍失败就降并发或升套餐 | | `4004` | 快递并发超限 | 等上一个请求返回再发下一个 | | `5002` | 上游暂时不可用 | 稍后重试 | 业务失败(`code != 0`)**不扣积分**。 ## 超时设置 快递接口要实时询问多家上游,未命中缓存时 **30 秒以上是正常的**。SDK 默认读取超时 60 秒,如果你自己改小了或者中间有网关,记得两边都留够: ```php $client->setTimeout(90, 5); // 读取 90 秒,连接 5 秒 ``` ```python client = AwiceClient(key, secret, timeout=90) ``` ## 计费 买套餐得积分,每次调用按接口类型扣分,用完或到期续。运价类接口单价不同(海运最低、快递最高,因为要实时问上游),字典类有免费额度。实时价格以[控制台](https://www.5688.cn/user/openapi/plans)为准——这里不写死数字,免得调价后对不上。 ## License MIT ## 船期查询与详情 有结果的搜索默认每次 1 积分、最多 50 条,空结果免费。每条返回 `schedule_id` 和 `terminals`。详情默认不重复收费,后台可调整;只接受同一应用搜索返回的标识,不能跨应用使用。数据字段缺失为 null,分段/挂靠港缺失为 [];船期不代表舱位。详情查无 data=[]。 ```python page = client.schedule(pol="CNSZX", pod="USLAX", carrier="COSCO", limit=50) rows = page.get("data", []) if rows: detail = client.schedule_detail(rows[0]["schedule_id"]) print(detail.get("legs", []) if detail else []) ``` ```php $page = $client->schedule(["pol" => "CNSZX", "pod" => "USLAX", "limit" => 50]); if (!empty($page['data'])) { $detail = $client->scheduleDetail($page['data'][0]['schedule_id']); } ``` 接口:POST /openapi/v1/schedule/search、POST /openapi/v1/schedule/detail。 文档:https://www.5688.cn/open/docs/schedule#detail ## 四类物流下单(0 积分) 沿用 /api/openapi/v1/,AppKey 绑定的官网客户须完成实名认证。 四类下单、下单选项、本人订单详情固定免费,零积分余额可用,仍签名鉴权并限速。 提交会生成真实订单,进入与官网相同的后台业务流程。 | PHP 方法 | Python 方法 | Java 方法 | 相对路径 | | --- | --- | --- | --- | | createOceanOrder($payload) | create_ocean_order(**payload) | createOceanOrder(payload) | POST /orders/ocean/create | | createAirOrder($payload) | create_air_order(**payload) | createAirOrder(payload) | POST /orders/air/create | | createExpressOrder($payload) | create_express_order(**payload) | createExpressOrder(payload) | POST /orders/express/create | | createFbaOrder($payload) | create_fba_order(**payload) | createFbaOrder(payload) | POST /orders/fba/create | | orderOptions(['order_type'=>'ocean']) | order_options(order_type="ocean") | orderOptions(Map.of("order_type", "ocean")) | GET /orders/options | | orderDetail(['order_type'=>'ocean','client_order_no'=>'MY-ORDER-001']) | order_detail(order_type="ocean", client_order_no="MY-ORDER-001") | orderDetail(params) | POST /orders/detail | 先取下单选项再填 payload。海运港口使用字典内部 code,空运使用机场 IATA 码。 联系人可用自己的联系人 ID,或内嵌 company/contact/tel/address 对象。 [完整参数与四类示例](https://www.5688.cn/open/docs/orders)。 client_order_no 为必填外部单号,在同一客户、同一订单类型内唯一,跨应用共用。 原单号、原有效参数重试返回原订单(replayed=true);原单号改变内容返回 HTTP409 / code1003。 超时后先按原单号查订单,再用原内容重试,避免换单号造成重复下单。SDK 每次请求自动生成新 nonce 和时间戳。 PHP/Python 单文件 SDK 返回 data;Java 返回 ApiResponse,可用 getData() / getEnvelope() 获取业务数据或完整响应;PHP/Python 下载包返回完整 code/data/credit_used 响应。 本次更新下载源码,不代表已向 Composer / PyPI 发布新版本。