增值税发票在线查验 API 怎么接入:Base64 图片上传、返回字段与工程实践

简介: 本文介绍阿里云市场增值税发票在线查验接口的技术接入方式:支持通过 imgBase64 或 imgUrl 传入发票图片,服务端完成 OCR 识别并联网核验后返回发票代码、号码、金额、购销方信息等结构化字段。文中给出请求参数表、完整 JSON 返回样例、常见 HTTP 与业务错误码排查方法,并提供 curl、Python、Node.js、Java、PHP 多语言示例,以及重试、缓存、限流等工程实践建议。

增值税发票在线查验 API 技术接入指南

封面图

1. 背景与适用场景

在企业财务、费用报销、电子发票归档等场景中,经常需要对纸质或电子发票进行真伪核验与票面信息提取。传统人工核对方式效率低、易出错,而通过 API 将发票图片传入服务端,由服务端完成 OCR 识别并联网核验,是一种常见的工程化方案。

本接口适合以下场景:

  • 报销系统:员工上传发票后自动提取发票代码、号码、金额等字段。
  • 财务对账:批量核对销方、购方、价税合计等信息。
  • 发票归档:将纸质发票扫描件结构化存储,便于检索与审计。

说明:本接口为阿里云市场入驻服务商提供的数据服务,正文示例中的鉴权头与调用路径均按阿里云 API 网关标准接入。

2. 接口概览

  • 调用方式:POST
  • 路径:/ocrCheckVAT
  • 协议:HTTPS
  • 返回格式:JSON
  • 鉴权方式:阿里云 API 网关 APPCODE 简单身份认证,请求头:Authorization: APPCODE <appcode>

请求体中传入发票图片的 Base64 编码或图片 URL,服务端完成识别与核验后返回票面结构化字段。完整调用地址请在阿里云控制台查看。

接口概览

3. 请求参数

字段名 类型 必填 说明
imgBase64 string 发票图片的 Base64 字符串,与 imgUrl 二选一
imgUrl string 发票图片的可访问下载地址,与 imgBase64 二选一

注意:imgBase64 与 imgUrl 必须且只能传一个。建议优先使用 Base64,避免图片外链失效或被限制访问。

4. 返回结构

顶层返回结构统一如下:

字段名 类型 说明
showapi_res_code int 接口调用是否成功,0 为成功,其他为失败
showapi_res_error string 错误提示信息
showapi_res_id string 请求唯一标识
showapi_res_body object 业务数据主体

showapi_res_body 内部字段:

字段名 类型 说明
ret_code int 业务调用结果,0 为成功
remark string 提示信息
invoiceType string 发票类型
invoiceCode string 发票代码
invoiceNo string 发票号码
invoiceDate string 开票日期
buyerName string 购方名称
buyerTaxNo string 购方税号
buyerContact string 购方地址电话
buyerBank string 购方开户行账户
salerName string 销方名称
salerTaxNo string 销方税号
salerContact string 销方地址电话
salerBank string 销方开户行账户
invoiceAmt string 合计金额
totalTaxAmt string 合计税额
totalAmt string 价税合计
notes string 发票备注
status int 发票状态:1 未作废、2 作废、3 红冲
itemList array 商品明细列表

itemList 每项字段:

字段名 类型 说明
name string 商品名称
amount string 数量
spec string 规格
unit string 单位
taxAmt string 税额
taxRate string 税率
priceAmt string 金额
priceUnit string 单价

成功响应示例:

{
   
  "showapi_res_code": 0,
  "showapi_res_error": "",
  "showapi_res_id": "",
  "showapi_res_body": {
   
    "ret_code": 0,
    "remark": "核验成功",
    "invoiceType": "增值税普通发票(电子)",
    "invoiceCode": "031*****411",
    "invoiceNo": "28*****251",
    "invoiceDate": "2019-01-01",
    "buyerName": "孟**",
    "buyerTaxNo": "",
    "buyerContact": "",
    "buyerBank": "",
    "salerName": "上海***有限公司",
    "salerTaxNo": "913*****40M",
    "salerContact": "上海市普陀区...",
    "salerBank": "",
    "invoiceAmt": "2891.98",
    "totalTaxAmt": "28.92",
    "totalAmt": "2920.90",
    "notes": "",
    "status": 1,
    "itemList": [
      {
   
        "name": "*信息技术服务*数据服务费",
        "spec": "API-AL",
        "unit": "项",
        "amount": "1.0",
        "taxRate": "0.01",
        "taxAmt": "28.92",
        "priceAmt": "2891.98",
        "priceUnit": "2891.980198019801980"
      }
    ]
  }
}

返回结构

5. 错误码与排查

接口存在两类错误:网关层 HTTP 状态码与业务层 ret_code / remark。

常见 HTTP 状态码:

状态码 含义 可能原因 排查办法
400 请求参数错误 缺少 imgBase64/imgUrl,或图片格式不支持 检查请求体是否包含有效图片字段
401 身份校验失败 APPCODE 缺失、错误或未启用该 API 在控制台确认 APPCODE 与授权状态
403 请求被禁止 剩余次数已用完或接口未购买 查看控制台余量与有效期
404 服务地址不存在 路径拼写错误 核对路径 /ocrCheckVAT
500 服务端内部错误 服务商端异常 稍后重试或联系平台
503 服务暂不可用 限流或维护 降低调用频率,稍后重试

业务层失败返回示例:

{
   
  "showapi_res_code": 0,
  "showapi_res_error": "",
  "showapi_res_body": {
   
    "ret_code": -1,
    "remark": "查验不一致!"
  }
}

常见业务提示:

  • "查验不成功,请重试。":服务商端核验超时或网络波动,可稍后重试。
  • "查验不一致!":票面信息与税局底账不一致。
  • "查无此票!":税局系统中未找到该发票记录。
  • "超过该张发票当日查验次数":单张发票当日查验次数已达上限,次日再试。

6. 频控与合规

  • 调用频次:具体 QPS 上限以阿里云控制台实时配置为准。
  • 次数扣减:当 HTTP 响应状态码为 200 时扣减调用次数;非 200 状态码不扣减。
  • 数据合规:发票图片属于敏感经营数据,传输请使用 HTTPS,并避免在日志中完整留存图片 Base64。核验结果仅用于业务校验,不作为唯一法律依据。
  • 缓存策略:发票状态在短时间内通常不变,对同一张发票的核验结果可做短时缓存(如 5~15 分钟),以减少重复调用。

适用场景

7. 多语言接入示例

curl

curl -X POST '<调用地址>/ocrCheckVAT' \
  -H 'Authorization: APPCODE <YOUR_APPCODE>' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'imgBase64=<BASE64_IMAGE_STRING>'

Python

import base64
import requests


def verify_invoice(image_path: str, appcode: str, endpoint: str):
    with open(image_path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("utf-8")

    url = f"{endpoint}/ocrCheckVAT"
    headers = {
   "Authorization": f"APPCODE {appcode}"}
    resp = requests.post(
        url, data={
   "imgBase64": b64}, headers=headers, timeout=30
    )
    return resp.json()


# 使用示例
result = verify_invoice("invoice.jpg", "<YOUR_APPCODE>", "<调用地址>")
print(result["showapi_res_body"]["remark"])

Node.js

const fs = require('fs');
const axios = require('axios');

async function verifyInvoice(imagePath, appcode, endpoint) {
   
  const b64 = fs.readFileSync(imagePath, {
    encoding: 'base64' });
  const url = `${
     endpoint}/ocrCheckVAT`;
  const headers = {
    Authorization: `APPCODE ${
     appcode}` };
  const data = new URLSearchParams({
    imgBase64: b64 });
  const resp = await axios.post(url, data, {
    headers, timeout: 30000 });
  return resp.data;
}

Java

// 省略依赖引入,示例使用 JDK HttpClient + Jackson
public Map<String, Object> verifyInvoice(
        String imagePath, String appcode, String endpoint) throws Exception {
   
    byte[] bytes = Files.readAllBytes(Paths.get(imagePath));
    String b64 = Base64.getEncoder().encodeToString(bytes);

    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(endpoint + "/ocrCheckVAT"))
        .header("Authorization", "APPCODE " + appcode)
        .header("Content-Type", "application/x-www-form-urlencoded")
        .POST(HttpRequest.BodyPublishers.ofString(
            "imgBase64=" + URLEncoder.encode(b64, StandardCharsets.UTF_8)))
        .build();

    HttpResponse<String> response = client.send(
        request, HttpResponse.BodyHandlers.ofString());

    return new ObjectMapper().readValue(
        response.body(), new TypeReference<Map<String, Object>>() {
   });
}

PHP

<?php
$appcode = '<YOUR_APPCODE>';
$endpoint = '<调用地址>';
$imagePath = 'invoice.jpg';
$b64 = base64_encode(file_get_contents($imagePath));

$ch = curl_init("{$endpoint}/ocrCheckVAT");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['imgBase64' => $b64]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: APPCODE {$appcode}"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
echo $data['showapi_res_body']['remark'];
?>

在线调试

8. 工程实践建议

  1. 前置校验:调用前检查图片大小与格式,建议压缩至 2MB 以内,避免 Base64 过大导致请求超时。
  2. 参数二选一:代码中显式校验 imgBase64 与 imgUrl 有且仅有一个,否则直接返回参数错误。
  3. 超时与重试:建议设置 30 秒超时;当返回 503 或 "查验不成功,请重试。" 时,采用指数退避重试 2~3 次。
  4. 结果缓存:对同一张发票的核验结果做幂等缓存,键可设为 发票代码_发票号码,TTL 5~15 分钟。
  5. 密钥管理:APPCODE 不要硬编码在前端或公开仓库,通过环境变量或密钥管理服务注入。
  6. 敏感数据:日志中不要打印完整 Base64 字符串;返回结果中购方/销方信息按需脱敏展示。
  7. 限流保护:客户端实现令牌桶或固定窗口限流,避免突发流量触发网关限流。

工程实践

9. 技术 FAQ

Q1:可以同时传 imgBase64 和 imgUrl 吗?
不建议。两个参数二选一,服务端以其中一个为准;同时传入可能造成请求体过大。

Q2:图片格式有要求吗?
通常支持 JPG、PNG、BMP 等常见图片格式。建议上传清晰、完整的电子发票 PDF 转图或拍照件。

Q3:为什么返回 "查无此票"?
可能原因:发票尚未同步至税局系统;输入图片模糊导致 OCR 识别错误;发票状态异常。建议核对图片清晰度与票面信息。

Q4:HTTP 200 但 ret_code 不为 0 是否扣次数?
根据该接口的次数扣减规则,HTTP 状态码为 200 时即视为一次成功调用并扣减剩余次数。因此 ret_code 不为 0 的业务失败(如查无此票)仍会扣减次数。

Q5:如何降低调用成本?
对高频重复核验场景使用短时缓存;批量处理前先做参数校验与去重;设置合理的限流策略。

10. 小结

本文围绕增值税发票在线查验接口,介绍了其适用场景、请求参数、返回结构、常见错误码以及多语言接入示例。接入时需注意:

  • 仅传 imgBase64 或 imgUrl 之一;
  • 使用 Authorization: APPCODE <appcode> 鉴权;
  • 完整调用地址、QPS 与收费规则以阿里云控制台为准;
  • 对敏感发票图片与核验结果做好传输加密、日志脱敏与缓存控制。

通过合理的重试、缓存与限流设计,可将该能力稳定集成到财务、报销或发票归档系统中。

相关文章
|
4天前
|
人工智能 自然语言处理 安全
阿里云AI数智鉴密:AI 生成内容如何拿到一张"防篡改的身份证"
隐形水印 + C2PA签名:让AI生成内容“持证上岗”。
1122 0
|
13天前
|
人工智能 自然语言处理 安全
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考
本文聚焦阿里云2026年推出的三款自研AI办公产品,清晰拆解千问办公、Qoder Teams、Qoder CN的差异化定位与能力边界:千问办公主打职场全场景提效,支持自然语言指令一键完成PPT生成、数据分析等高频办公任务;Qoder Teams面向程序员团队,深度整合AI代码生成、团队协同与企业知识库能力;Qoder CN则专为金融、政务等强合规场景打造,实现数据不出境与VPC私有化部署。文章同步给出分场景选型指南与最新活动定价,帮助不同类型的企业按需组合产品,实现业务岗、研发岗与强合规场景的AI能力全覆盖。
3737 4
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考
|
4天前
|
人工智能 运维 BI
阿里云千问办公QwenWork深度解析:基于Qwen3.8,六大核心能力重构企业全自动化工作流与计费选型指南
传统AI办公工具大多停留在对话问答、文档摘要、简单文案生成层面,只能完成单点碎片化任务,无法自主拆解复杂业务流程,很难串联多工具、多文档、外部业务系统完成端到端完整工作交付。很多企业在落地AI办公的时候,需要组合多款不同工具,来回切换界面,手动复制粘贴中间结果,智能化改造落地门槛居高不下。千问办公QwenWork是整合多款智能体产品能力打造的一体化企业办公智能体平台,底层基座依托Qwen3.8大模型,打通桌面端Agent、云端Agent、企业协同Agent三种运行形态,不再局限简单问答,接收业务目标之后自主拆解任务步骤,调用各类工具,处理文档、表格、浏览器自动化、数据查询,直接输出可交付的办公
1355 0
|
4天前
|
人工智能 安全 前端开发
刚刚 GPT-6 Astra 发布,全球最强,AGI 时代到来!
OpenAI 正式推出 GPT-6 Astra 模型,带大家看看这次 GPT 有哪些提升,跟 Claude Fable 5.1 有什么差距?AI 编程能力如何?AGI 真的来了么?
612 0
|
10天前
|
人工智能 并行计算 数据可视化
秋叶ComfyUI-AKI最新整合包|完整部署教程+核心指令手册
秋叶ComfyUI-AKI一键整合包,国内适配最优、稳定性最强的商用/学习级版本:全封装虚拟环境、预装90%常用节点、内置绘世启动器与成熟工作流,免配置、零依赖、解压即用,完美兼顾新手入门与专业批量生产需求。(239字)
|
14天前
|
人工智能 Linux iOS开发
Ollama使用教程:Ollama官网下载、Ollama本地部署大模型(2026最新)
Ollama 是一款免费开源的本地大模型运行工具,支持在 Windows/macOS/Linux 上离线运行 Qwen、DeepSeek、Llama 等主流开源模型,数据不出本机、隐私安全。提供 OpenAI 兼容 API,命令行一键拉取/运行/管理模型,无需联网,无调用限制,是开发者与 AI 爱好者部署本地 AI 助手的理想选择。(239 字)