开发文档

了解如何将易开票服务集成到您的应用中

使用Web链接开票

集成流程

  1. 您的系统生成开票所需参数 (如金额, 订单号, 商品名称, 回调URL等)。
  2. 使用我们提供的加密方案 (见参数加密部分),将参数和您的应用凭证 (appid, appsecret) 加密生成一个安全的开票链接。
  3. 用户点击该链接,跳转到我们的开票页面。页面会安全地解密并展示订单金额等信息。
  4. 用户在页面上填写或确认发票抬头信息 (支持通过企业名称自动查询填充)。
  5. 用户提交开票请求。
  6. 系统处理开票,并将最终结果 (成功或失败) 通过您预设的回调URL异步通知到您的系统 (见回调处理部分)。

主要优势

  • 无需自行开发复杂的前端开票界面和企业信息查询功能。
  • 通过加密链接传递参数,安全可靠。
  • 用户体验友好,支持自动填充抬头信息。
  • 通过异步回调实时获取开票结果。

应用管理

要开始集成,您首先需要在我们的平台创建一个应用。系统会自动为您的应用生成安全凭证:

  • App ID (应用ID): appid,应用的唯一标识符,用于标识请求来源。
  • App Secret (应用密钥): appsecret,用于参数加密和签名验证,请务必妥善保管,切勿泄露

您可以在登录后的"应用管理"页面创建新应用、查看和管理您的应用凭证,并设置接收开票结果的回调URL。

URL参数加密方案

为了确保通过URL传递参数的安全性,我们采用 AES-CBC + HMAC-SHA256 的组合方案。

加密步骤

  1. 将所有业务参数 (如 amount, order_number 等) 构造成一个字典。
  2. 对参数字典进行URL编码 (例如: amount=100.00&order_number=ORD123)。
  3. 使用 appsecret 的MD5哈希值作为AES加密的密钥 (16字节)。
  4. 生成一个随机的16字节初始化向量 (IV)。
  5. 使用AES-CBC模式,配合IV和AES密钥,对URL编码后的参数字符串进行加密。
  6. 将 IV 拼接到加密后的数据前面 (iv + encrypted_data)。
  7. 对拼接后的完整数据 (iv + encrypted_data) 进行Base64编码,得到最终的 data 参数值。
  8. 使用原始的 appsecret 作为密钥,对拼接后的完整数据 (iv + encrypted_data) 计算HMAC-SHA256签名,得到 signature 参数值。

最终URL结构

将加密和签名后的参数附加到基础URL后:

http://tax.dsoou.com/orders/checkout/?appid=您的AppID&data=Base64编码后的加密数据&signature=HMAC签名

需要加密的参数

参数名 类型 必填 说明
amount string 开票金额 (不含税),字符串格式,例如 "100.00"。
tax_rate string 税率, 例如 "0.06"
order_number string 您的系统内部订单号,用于关联开票记录。
product_name string 商品或服务名称,将显示在发票上。
timestamp string 当前UNIX时间戳 (秒),字符串格式。用于防止重放攻击。
callback_url string 用户完成开票操作后的前端跳转URL。如果未提供,将使用您在应用设置中配置的默认回调URL。

* 推荐使用 Python 的 `pycryptodome` 库来实现 AES 和 HMAC 操作。

回调处理

开票完成后,无论是成功还是失败,系统都会向您在应用设置中指定的 `notify_url` 发送一个 POST 请求,通知您开票结果。通知数据同样采用加密和签名保护。

通知机制

  • 通知请求的 Content-Type 为 `application/json`。
  • 请求体包含 `appid`, `data` (Base64加密数据), `signature` (HMAC签名)。
  • 您需要使用与加密时相同的 `appsecret` 来解密 `data` 并验证 `signature`。
  • 解密后的数据包含订单号、开票状态 (`status`: "SUCCESS" 或 "FAILED")、时间戳以及可能的失败原因 (`failed_reason`)。
  • 为保证通知送达,如果您的接口未返回成功响应 (HTTP状态码 2xx),系统会进行重试 (最多3次,间隔递增)。请确保您的接口具有幂等性,能正确处理重复通知。
  • 您的回调接口在成功处理通知后,应返回 HTTP 200 OK。

解密与验签

解密回调数据的步骤与加密过程相反:

  1. 从请求体获取 `appid`, `data`, `signature`。
  2. 根据 `appid` 查找对应的 `appsecret`。
  3. 对 Base64 编码的 `data` 进行解码,得到原始的加密字节串 (iv + encrypted_data)。
  4. 使用 `appsecret` 和收到的加密字节串计算 HMAC-SHA256 签名,并与请求中的 `signature` 进行比较 (使用 `hmac.compare_digest` 防止时序攻击)。
  5. 如果签名验证通过,提取加密字节串的前16字节作为 IV,剩余部分为实际加密数据。
  6. 使用 `appsecret` 的MD5哈希作为AES密钥,配合IV,解密实际加密数据。
  7. 对解密后的数据进行 unpadding 操作。
  8. 将解密后的字节串解码为 UTF-8 字符串,并解析为参数字典。
  9. 重要:验证解密后参数中的 `timestamp` 是否在合理时间范围内 (例如5分钟内),以防止重放攻击。

通过API开票

除了通过Web链接引导用户开票,您也可以直接通过调用我们的API来实现开票和订单查询功能。这种方式更适合后端系统集成。

API认证

所有API调用都需要进行身份认证,我们采用基于 HMAC签名 的认证方式,以确保请求的安全性和完整性,并避免直接传输您的 appsecret

请求头要求

在每个API请求的HTTP Header中,您需要包含以下字段:

X-App-ID: 您的应用ID
X-Timestamp: 当前UNIX时间戳 (秒,字符串)
X-Nonce: 随机字符串 (可选, 建议包含以增加安全性)
X-Signature: 计算得出的请求签名 (十六进制字符串)

签名算法

签名通过以下方式计算:

  1. 构建原始字符串 (raw_string),其格式为:appid + timestamp + nonce + 请求路径
    例如: your_appid1622548800randomstring/api/create-invoice/
  2. 使用您的 appsecret 作为密钥,对 raw_string 计算 HMAC-SHA256 哈希值。
  3. 将计算得到的二进制哈希值转换为十六进制字符串,即为最终的 X-Signature

* 时间戳 (X-Timestamp) 的有效期为5分钟,请确保您的服务器时间准确。

* 请求路径 (request.path) 是指API的相对路径,例如 /api/create-invoice//api/orders/

API端点

创建开票请求

POST /api/orders/create-invoice/

用于提交一个新的开票请求。

请求体 (Request Body - JSON)

包含订单和发票抬头信息,必填字段与Web链接加密参数类似,但不需要包含 timestampcallback_url (notify_url 在创建 App 时设置)。

字段名 类型 必填 说明
order_number string 您的订单号
product_name string 商品名称
amount string 开票金额 (不含税), 例如 "123.45"
tax_rate string 税率, 例如 "0.06"
organization_name string 公司名称 (发票抬头)
tax_number string 纳税人识别号
address string 公司地址
phone string 公司电话
bank_account string 银行账号
bank_name string 开户行名称
is_test boolean 是否为测试发票

如果 is_testtrue,则发票为测试发票,不会实际开票,但会返回成功状态。

成功响应 (Success Response - HTTP 200 Created)

返回创建的订单详情,包含系统生成的 `uuid` 和发票信息。

{
                        "is_success": true,
                        "order": {
                            "uuid": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
                            "order_number": "YOUR_ORDER_123",
                            "product_name": "服务费",
                            "amount": "100.00",
                            "tax_rate": "0.06",
                            "organization_name": "示例公司",
                            "tax_number": "91310000MA1FN1X000",
                            "status": "SUCCESS",
                            "app_name": "我的应用",
                            "invoice_number": "发票号码",
                            "invoice_date": "开票日期",
                            "invoice_links": {
                                "pdf": "",
                                "xml": "",
                            },
                            "created_at": "2023-10-27 10:00:00",
                            "updated_at": "2023-10-27 10:00:00",
                            ...
                        }
                      }
失败响应 (Error Response)

- HTTP 200: 请求数据验证失败 (如缺少必填字段,格式错误, 或服务异常)。

{
                        "is_success": false,
                        "error_message": "缺少必填字段: order_number",
                        }

- HTTP 403 Forbidden: 认证失败 (签名错误、AppID无效、时间戳过期等)。

查询订单列表

GET /api/orders/

获取当前认证应用下的所有订单列表。

成功响应 (Success Response - HTTP 200 OK)

返回一个包含订单对象的数组。

[
    {
        "uuid": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
        "order_number": "YOUR_ORDER_123",
        "product_name": "服务费",
        "amount": "100.00",
        "status": "SUCCESS",
        "order_status": "成功",
        "app_name": "我的应用",
        "created_at": "2023-10-27T10:00:00Z",
        ...
    },
    ...
]

查询单个订单详情

GET /api/orders/{uuid}/

根据订单的 UUID 获取订单详细信息。

成功响应 (Success Response - HTTP 200 OK)

返回单个订单对象的详细信息,结构同创建订单的成功响应。

失败响应 (Error Response)

- HTTP 404 Not Found: 指定 UUID 的订单不存在或不属于当前认证的应用。

回调处理

通过API创建的开票请求,其结果通知方式与 Web链接开票的回调处理 完全相同。系统会向您在应用设置中配置的 `notify_url` 发送包含加密结果的POST请求。

请参考Web链接方式下的回调处理说明来接收、解密和验证通知数据。

通用

安全注意事项

  • 密钥安全: 您的 appsecret 是最高机密,切勿硬编码在客户端代码或版本控制中,也绝不能在网络中明文传输。
  • HTTPS: 强烈建议所有与我们平台的交互 (包括Web链接跳转和API调用) 都通过HTTPS进行,以保证传输层安全。
  • 时间戳验证: 在处理回调通知和生成API请求签名时,务必使用并验证时间戳,设置合理的有效期 (如5分钟),以防止重放攻击。
  • 签名验证: 对于接收到的回调通知,务必严格验证其HMAC签名,确保数据未被篡改且来源可靠。
  • 输入验证: 对所有用户输入和来自API的参数进行严格验证和清理,防止注入等攻击。
  • 回调接口幂等性: 确保您的回调处理接口具有幂等性,能够正确处理可能发生的重复通知。
  • 密钥轮换: 如需更高安全性,可考虑实施应用密钥的定期轮换机制。

错误码说明

在集成过程中,您可能会遇到以下常见的错误响应 (通常在Web链接参数解析或API认证失败时返回,HTTP状态码通常为 400 或 403):

错误消息 (detail) 可能原因
appid is required Web链接缺少 appid 参数 / API请求头缺少 X-App-ID
signature is required Web链接缺少 signature 参数 / API请求头缺少 X-Signature
data is required Web链接缺少 data 参数。
timestamp is required API请求头缺少 X-Timestamp
Invalid appid 提供的 appid 不存在或对应的应用已被禁用。
data validation failed Web链接参数解密失败或签名验证失败。请检查 appsecret 和加密过程。
Invalid signature API请求签名验证失败。请检查签名计算方法、appsecret、时间戳和请求路径。
Timestamp expired API请求的时间戳已超过有效范围 (当前为5分钟)。请检查客户端与服务器时间同步。

需要帮助?

如果您在集成过程中遇到任何问题,请随时联系我们的技术支持团队。

联系技术支持