返回商户后台
版本v1

SMPAY OPENAPI

订单接口文档

用于创建支付订单、查询订单状态,以及接收订单终态通知。所有金额均为人民币,保留两位小数并向下取整。

接口地址https://<您的域名>/api/v1
数据格式JSON / UTF-8
认证方式HMAC-SHA-256

认证与签名

每个商户固定一把 API 密钥。请仅保存在服务端环境变量,不能放入浏览器、小程序或 App 客户端。

固定 API 密钥

商户始终只有一把生效中的 API 密钥。刷新后,新请求立即使用新密钥,旧密钥不能再调用 OpenAPI;请求签名不需要传递密钥版本。

请求头 必填 说明
Content-Type 创建订单必填 固定为 application/json。
X-SMPAY-Merchant-Code 是 商户编号。
X-SMPAY-Timestamp 是 10 位 Unix 时间戳(秒)。与平台时间相差不得超过 300 秒。
X-SMPAY-Nonce 是 每次请求唯一的 16-128 位随机字符串,可使用字母、数字、下划线和连字符。
X-SMPAY-Signature 是 签名结果,64 位小写十六进制 HMAC-SHA-256。
X-SMPAY-Idempotency-Key 条件必填 创建订单未传商户订单号时必须传。16-128 位字母、数字、点、下划线或连字符。
签名原文(每行以 LF 换行)
HTTP_METHOD
PATH
TIMESTAMP
NONCE
SHA256(REQUEST_BODY)

使用当前 API 密钥作为 HMAC-SHA-256 的密钥。创建订单签名的是原始 JSON 字节;查询订单没有请求体,最后一行是空字符串的 SHA-256。查询时的 PATH 必须包含原始查询串(包括参数顺序和 URL 编码)。

POST

创建订单

/api/v1/orders。平台会校验商户状态、金额、地区、通道额度与收款用户可用余额后分配收款通道。

请求参数

字段 类型 必填 说明
merchant_order_no string 否 商户订单号,等同 out_trade_no;最长 64 字符。同一商户内唯一。两者同时传时必须相同。
out_trade_no string 否 merchant_order_no 的兼容别名。不要同时传不同值。
payment_method string 是 alipay(支付宝)、wechat(微信)或 aggregate_qr(聚合码)。
amount number/string 是 订单金额,最小 0.01,按两位小数向下取整。
province string 是 省份,最长 32 字符。与管理后台的地区匹配模式共同决定可用通道。
city string 是 城市,最长 32 字符。
subject string 是 订单标题,最长 128 字符。
notify_url string 否 订单状态通知地址,必须为安全的 HTTPS 公网地址。
attach string 否 商户自定义回传字段,最长 256 字符;原样返回在查询与回调中。
请求示例
{
  "merchant_order_no": "M202609240001",
  "payment_method": "alipay",
  "amount": "100.00",
  "province": "广东省",
  "city": "深圳市",
  "subject": "会员充值",
  "notify_url": "https://merchant.example.com/smpay/notify",
  "attach": "user_10086"
}

成功响应

HTTP 200
{
  "code": 0,
  "message": "ok",
  "data": {
    "platform_order_no": "SM240924001",
    "merchant_order_no": "M202609240001",
    "status": "processing",
    "payment_method": "alipay",
    "payment_method_name": "支付宝",
    "amount": "100.00",
    "currency": "CNY",
    "province": "广东省",
    "city": "深圳市",
    "subject": "会员充值",
    "attach": "user_10086",
    "payment_info": { "channel_name": "张**的支付宝", "qrcode_url": "/uploads/channels/0123456789abcdef0123456789abcdef.png" },
    "created_at": "2026-09-24 10:36:12",
    "expires_at": "2026-09-24 10:41:12",
    "timeout_seconds": 300
  }
}

重复提交相同商户订单号或幂等键会返回原订单,不会重复冻结余额或重复分配通道。未提供商户订单号时,平台会生成 MO... 商户订单号。

GET

查询订单

/api/v1/orders/query。仅可查询当前商户自身的订单。

查询参数 必填 说明
platform_order_no 二选一 平台订单号,例如 SM240924001。
merchant_order_no 二选一 商户订单号。
out_trade_no 否 merchant_order_no 的兼容别名。不得与其传递不同值。

三个参数最终只能定位一个订单;请求头、签名规则与创建订单相同,查询请求的签名 PATH 必须包含完整查询串,正文为空字符串。

成功响应
{
  "code": 0,
  "message": "ok",
  "data": {
    "platform_order_no": "SM240924001",
    "merchant_order_no": "M202609240001",
    "status": "completed",
    "payment_method": "alipay",
    "payment_method_name": "支付宝",
    "amount": "100.00",
    "currency": "CNY",
    "province": "广东省",
    "city": "深圳市",
    "subject": "会员充值",
    "attach": "user_10086",
    "qrcode_url": "/uploads/channels/0123456789abcdef0123456789abcdef.png",
    "created_at": "2026-09-24 10:36:12",
    "expires_at": "2026-09-24 10:41:12",
    "completed_at": "2026-09-24 10:38:20",
    "cancelled_at": null,
    "refunded_at": null,
    "refund_amount": null
  }
}

回调通知

订单进入已完成、已取消或已退回状态时,平台向订单创建时传入的 notify_url 发送 JSON 回调。未填写回调地址时,请通过查询订单接口获取状态。

接收方必须幂等

按 event_id 去重,并以较大的 event_sequence 覆盖较旧事件。收到任意 2xx 即视为成功。

回调请求头

请求头 说明
Content-Type application/json
X-SMPAY-Signature 使用固定 API 密钥对原始回调请求体计算的 HMAC-SHA-256 小写摘要。
X-SMPAY-Event-Id 与请求体 event_id 一致。
X-SMPAY-Key-Version 回调签名所用密钥的版本号。刷新 API 密钥后,已入队事件仍使用创建时的版本。

回调参数

字段 类型 说明
event_id string 全局唯一事件标识,用于幂等。
event_type string order.completed、order.cancelled、order.refunded。
event_sequence integer 同一订单递增事件序号。
occurred_at string 状态发生时间,格式 Y-m-d H:i:s。
platform_order_no string 平台订单号。
merchant_order_no string 商户订单号。
merchant_code string 商户编号。
status string completed、cancelled 或 refunded。
amount string 订单金额,两位小数。
currency string 固定 CNY。
payment_method string 支付方式编码。
subject string 订单标题。
attach string 创建订单时的回传字段。
completed_at string/null 完成时间,仅已完成时有值。
cancelled_at string/null 取消时间,仅已取消时有值。
refunded_at string/null 退回时间,仅已退回时有值。
refund_amount string/null 全额退回金额,仅已退回时有值。
已完成回调示例
{
  "event_id": "evt_01J8SMPAY0001",
  "event_type": "order.completed",
  "event_sequence": 1,
  "occurred_at": "2026-09-24 10:38:20",
  "platform_order_no": "SM240924001",
  "merchant_order_no": "M202609240001",
  "merchant_code": "XH202609",
  "status": "completed",
  "amount": "100.00",
  "currency": "CNY",
  "payment_method": "alipay",
  "subject": "会员充值",
  "attach": "user_10086",
  "completed_at": "2026-09-24 10:38:20",
  "cancelled_at": null,
  "refunded_at": null,
  "refund_amount": null
}

失败重试计划:首次立即发送;随后 1、5、15、30 分钟,1、3、6、12 小时,最多 9 次。网络异常、超时、408、429 和 5xx 会重试;其他 4xx 不重试。接收方返回 Retry-After 时,平台会采用不早于默认退避的等待时间。回调地址必须是可公开解析的 HTTPS 地址,不能指向内网或保留地址,且不跟随重定向。

密钥刷新后,请保留旧的回调验签密钥至少 24 小时,并按 X-SMPAY-Key-Version 选择密钥验签;新密钥只用于新的 API 请求和新创建的回调事件。

PHP SDK

SDK 会为每次请求生成新的时间戳和随机串;创建订单仅在提供稳定订单号或幂等键时自动重试。

唯一发布源

下载 PHP SDK。SDK 强制 HTTPS、校验证书、不跟随重定向,并读取 Retry-After。

验签与密钥轮换示例
$client = new SmpayClient($baseUrl, $merchantCode, $activeApiKey);
// 记录商户后台返回的 api_key_version,并保留旧回调密钥。
$client->setCallbackKey(3, $previousCallbackKey)
       ->setCallbackKey(4, $activeApiKey);

$isValid = $client->verifyCallbackRequest($rawBody, [
    'X-SMPAY-Signature' => $_SERVER['HTTP_X_SMPAY_SIGNATURE'] ?? '',
    'X-SMPAY-Event-Id' => $_SERVER['HTTP_X_SMPAY_EVENT_ID'] ?? '',
    'X-SMPAY-Key-Version' => $_SERVER['HTTP_X_SMPAY_KEY_VERSION'] ?? '',
]);

错误码与订单状态

所有接口统一返回 code、message 与 data。错误时 data 为 null。

HTTP 业务 code 含义
400 INVALID_JSON JSON 格式不正确。
401 UNAUTHORIZED 商户编号、签名或认证字段不合法。
401 TIMESTAMP_EXPIRED 时间戳超出 300 秒允许窗口。
403 IP_NOT_ALLOWED 管理后台已启用白名单,当前来源 IP 未命中 CIDR 规则。
409 REPLAY_DETECTED 随机串已被使用,请生成新的随机串后重试。
413 PAYLOAD_TOO_LARGE JSON 请求体超过 16 KiB。
415 UNSUPPORTED_MEDIA_TYPE 创建订单未使用 application/json。
422 INVALID_REQUEST 业务参数、订单状态或通道分配条件不满足。
422 IDEMPOTENCY_KEY_REQUIRED 未传商户订单号时缺少幂等键。
429 RATE_LIMITED 超过限流阈值;读取响应头 Retry-After 后重试。
processing
交易中
completed
已完成
cancelled
已取消
refunded
已退回

限流与 IP 白名单

平台会同时控制商户维度和来源 IP 维度的频率,避免影响通道分配和账务处理。

规则 阈值 处理方式
OpenAPI 入口(签名校验前) 同一来源 IP 每分钟 60 次 超限返回 HTTP 429、RATE_LIMITED 和 Retry-After。
创建订单 每商户每分钟 120 次
查询订单 每商户每分钟 300 次
开放 API 合计 同一来源 IP 每分钟 600 次(签名通过后)

IP 白名单默认关闭。管理后台保存并启用后,所有商户的 OpenAPI 只允许命中 CIDR 规则的来源 IP 调用;请勿依赖客户端自行传递的 X-Forwarded-For。

同时命中多条规则时,以更严格的阈值为准;同一出口 IP 的生产调用应按 60 次/分钟进行容量规划。