接入文档
接入文档 /交付与通知/回调通知

回调通知

开票、红冲、作废等操作都是异步完成的。在 开具发票 或 红冲 时传入 callbackUrl,EasyAPI 会在结果产生后以 POST 请求把发票信息推送到该地址。这是获取开票结果的推荐方式。

回调类型

callbackType 触发时机 response 内容
开票成功 蓝票开具成功(printState == 1) 蓝票对象
开票失败 蓝票或红票开票失败(state == -1),可在控制台「开票参数」中关闭失败回调 发票对象,failMsg 为失败原因
红冲成功 红票开具成功 红票对象(color == red),parentInvoice 为原蓝票
作废成功 纸质发票作废成功(cancelState == 2) 蓝票对象
作废失败 纸质发票作废失败 蓝票对象
审核驳回 控制台开启开票审核且审核驳回(auditState == -1) 蓝票对象,consoleReason 为驳回原因

请求格式

text
POST {callbackUrl}?algorithm=HMAC-SHA256&timestamp=1767225600
Content-Type: application/json;charset=UTF-8
invoice-sign: {签名}

{"callbackType":"开票成功","response":{...发票对象...},"responseType":"invoice"}
位置 名称 说明
Query algorithm 签名算法,固定 HMAC-SHA256
Query timestamp 回调发起时间,秒级时间戳
Header invoice-sign 签名,见 签名校验
Body responseType 对象类型:invoice 发票;平台型客户注册企业时为 shop(通知类型 商户审核结果)
Body callbackType 回调类型,见上表
Body response 发票对象,字段与 查询发票详情 相同
业务系统应以 outOrderNo + color 识别发票

请求体中的 response.outOrderNo 为开票时传入的外部订单号,response.color 区分蓝票 / 红票。回调可能因重试重复送达,请做好幂等处理。

回调示例

json
{
  "callbackType": "开票成功",
  "response": {
    "invoiceId": 10001,
    "color": "blue",
    "outOrderNo": "ORDER20260101001",
    "category": "全电电子普通发票",
    "state": 1,
    "auditState": 1,
    "printState": 1,
    "cancelState": 0,
    "redState": 0,
    "statements": "已开票",
    "price": 1000,
    "tax": 56.6,
    "purchaserName": "深圳市腾讯计算机系统有限公司",
    "purchaserTaxpayerNumber": "91440300708461136T",
    "printTime": "2026-01-01 10:00:35",
    "allElectronicInvoiceNumber": "26312000000000000001",
    "electronicInvoiceUrl": "https://.../invoice.pdf",
    "electronicInvoiceOfd": "https://.../invoice.ofd",
    "electronicInvoiceXml": "https://.../invoice.xml",
    "downloadUrl": "https://.../download",
    "failMsg": null,
    "invoiceItems": [
      { "lineNumber": 1, "name": "*生产生活服务*技术服务费", "no": "3040201010000000000", "number": 1, "price": 1000, "sum": 1000, "taxRate": 0.06, "tax": 56.6 }
    ],
    "...": "其余字段同查询发票详情"
  },
  "responseType": "invoice"
}

响应要求

业务系统收到回调后须返回 HTTP 200,且响应体为以下任一形式,EasyAPI 才认为回调成功:

  • 纯文本 ok(不区分大小写);
  • JSON 且 code 为 1 或 200,例如 {"code":1,"message":"ok"}。

其他响应(非 200、超时、响应体不符合要求)视为失败并进入重试。

重试规则

回调失败后按以下间隔重试,最多推送 8 次(首次 + 7 次重试),仍失败则该条回调标记为失效,可通过 手动触发回调 或 查询发票 补偿。

第几次重试 距上次间隔
1 2 分钟
2 10 分钟
3 10 分钟
4 1 小时
5 2 小时
6 6 小时
7 15 小时

同一张发票产生新结果时,尚未发送的旧回调会被删除,只推送最新状态。

签名校验

签名使用企业在控制台创建的 第一组密钥(按创建顺序)的 appKey / appSecret:

  1. 拼接签名串:appKey={appKey}&algorithm=HMAC-SHA256&timestamp={timestamp}&{path}&{body}
    • {timestamp} 为 Query 中的 timestamp;
    • {path} 为回调地址的路径部分,例如回调地址 https://www.example.com/invoice/callback?x=1 的 path 为 /invoice/callback;
    • {body} 为收到的请求体原文(JSON 字符串,不要重新序列化)。
  2. 以 appSecret 为密钥对签名串做 HMAC-SHA256,结果 Base64 编码。
  3. 与请求头 invoice-sign 比较,一致则校验通过。
java
String message = "appKey=" + appKey
    + "&algorithm=HMAC-SHA256&timestamp=" + timestamp
    + "&" + path
    + "&" + body;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
String sign = Base64.getEncoder().encodeToString(mac.doFinal(message.getBytes(StandardCharsets.UTF_8)));
boolean valid = sign.equals(request.getHeader("invoice-sign"));
javascript
const crypto = require('node:crypto')
const message = `appKey=${appKey}&algorithm=HMAC-SHA256&timestamp=${timestamp}&${path}&${rawBody}`
const sign = crypto.createHmac('sha256', appSecret).update(message, 'utf8').digest('base64')
const valid = sign === req.headers['invoice-sign']
注意

请使用请求体原始字符串参与签名。多数框架会先把 JSON 解析成对象,再序列化会改变字段顺序或数值格式,导致签名不一致。

手动触发回调

用于补偿:重新向指定地址推送某张发票的当前状态。

单张发票回调

GET/invoice/callback
参数 类型 必填 说明
appKey string 条件必填 服务密钥 Key,与 appSecret 成对使用;传了 accessToken 时可不传
appSecret string 条件必填 服务密钥 Secret
accessToken string 条件必填 访问令牌,通过 获取访问令牌 接口获取;传了 accessToken 则无需 appKey / appSecret
taxNumber string 必填 企业纳税人识别号,指定本次操作的开票企业;必须是该密钥已关联的企业
outOrderNo string 必填 外部订单号
color string 选填 blue(默认)/ red
callbackUrl string 选填 回调地址,不传使用发票记录中的回调地址;传了会更新发票的回调地址
callbackType string 选填 传 作废失败 时推送作废失败通知,不传按发票当前状态决定回调类型
json
{
  "code": 1,
  "message": "回调成功"
}

回调成功 表示回调任务已创建,实际推送异步进行。发票没有可推送的状态(例如仍在开票中)时不会产生回调。

批量回调

POST/invoice/batch-callback
参数 类型 必填 说明
appKey string 条件必填 服务密钥 Key,与 appSecret 成对使用;传了 accessToken 时可不传
appSecret string 条件必填 服务密钥 Secret
accessToken string 条件必填 访问令牌,通过 获取访问令牌 接口获取;传了 accessToken 则无需 appKey / appSecret
taxNumber string 必填 企业纳税人识别号,指定本次操作的开票企业;必须是该密钥已关联的企业
ids array 条件必填 发票 ID 数组,与 outOrderNos 至少传一个,最多 5000 个
outOrderNos array 条件必填 外部订单号数组,最多 5000 个
callbackUrl string 选填 回调地址,不传使用各发票记录中的回调地址
callbackType string 选填 同上
json
{
  "appKey": "你的appKey",
  "appSecret": "你的appSecret",
  "taxNumber": "91320211MA1WML8X6T",
  "outOrderNos": ["ORDER20260101001", "ORDER20260101002"],
  "callbackUrl": "https://www.example.com/invoice/callback"
}
message 说明
商户订单号不能为空 outOrderNo 为空
商户订单号蓝票不存在 / 红票不存在 发票不存在
xxxURL格式不正确 callbackUrl 不是合法 URL
一次最多回调5000个发票 超出批量上限
暂无数据 批量回调没有匹配的发票