增值税发票在线查验 API 怎么接入:图片上传、返回字段与工程实践
一、技术简介
增值税发票在线查验接口支持通过图片(Base64 或 URL)传入发票凭证,由服务端完成 OCR 识别并联网核验票面信息,返回发票代码、号码、开票日期、金额、购销方信息、商品明细等结构化字段。适用于报销系统自动填单、财务对账数据校验、电子发票归档结构化存储等技术场景。
接口通过阿里云 API 网关接入,鉴权方式采用 APPCODE 简单身份认证(请求头 Authorization: APPCODE <appcode>),返回 JSON 格式。
本文所有调用地址、QPS 上限与收费规则以阿里云控制台实时配置为准。

二、能力概览
| 能力项 | 说明 | 适用情形 |
|---|---|---|
| 发票图片 OCR 识别 | 支持 JPG/PNG/BMP 等常见格式,提取票面文本 | 纸质发票拍照、电子发票 PDF 转图 |
| 联网核验真伪 | 对接税局底账数据进行状态校验 | 报销审核、财务入账前真伪确认 |
| 结构化字段返回 | 发票代码、号码、金额、购销方、商品明细等 | 系统自动填单、数据比对 |
| Base64 / URL 双传参 | 二选一,支持本地文件转 Base64 或图片外链 | 内网环境与有公网访问条件的场景 |
三、适用场景
报销系统自动填单:员工上传发票图片后,系统自动调用接口提取票面字段,回填至报销表单,减少手工录入。
财务对账:批量核对销方、购方、价税合计等信息,与 ERP/财务系统账目比对。
电子发票归档:将纸质发票扫描件结构化存储,便于检索、审计与合规备查。

四、接入流程
4.1 请求参数表
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| imgBase64 | string | 否 | 发票图片的 Base64 字符串,与 imgUrl 二选一 |
| imgUrl | string | 否 | 发票图片的可访问下载地址,与 imgBase64 二选一 |
imgBase64 与 imgUrl 必须且只能传一个。建议优先使用 Base64,避免外链失效或被限制访问。
4.2 标准步骤
- 在阿里云控制台开通该 API,获取 APPCODE。
- 将发票图片转为 Base64(或准备可访问的图片 URL)。
- 构造 POST 请求,Header 携带
Authorization: APPCODE <appcode>。 - 发送请求,解析响应 JSON。
- 根据
ret_code判断核验结果,处理业务逻辑。
五、调用示例与返回结构
5.1 完整返回结构
{
"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"
}
]
}
}
showapi_res_body 字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| ret_code | int | 业务结果,0 为成功,非 0 为失败 |
| remark | string | 提示信息 |
| invoiceType | string | 发票类型 |
| invoiceCode | string | 发票代码 |
| invoiceNo | string | 发票号码 |
| invoiceDate | string | 开票日期(yyyy-MM-dd) |
| buyerName / salerName | string | 购方/销方名称 |
| buyerTaxNo / salerTaxNo | string | 购方/销方税号 |
| invoiceAmt | string | 合计金额(不含税) |
| totalTaxAmt | string | 合计税额 |
| totalAmt | string | 价税合计 |
| status | int | 发票状态:1 未作废、2 作废、3 红冲 |
| itemList | array | 商品明细列表 |

5.2 多语言调用示例
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 11+)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class InvoiceVerify {
public static void main(String[] args) throws Exception {
String imagePath = "invoice.jpg";
String appcode = "<YOUR_APPCODE>";
String endpoint = "<调用地址>";
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());
System.out.println(response.body());
}
}
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'];
?>

六、在线调试实录
6.1 请求参数设计
在阿里云控制台「API 调试」模块,选择 POST 方式,填入以下参数:
- Header:
Authorization: APPCODE <your_appcode> - Body(x-www-form-urlencoded):
imgBase64=<发票图片Base64>
6.2 响应解读
showapi_res_code: 0表示网关层调用成功。showapi_res_body.ret_code: 0表示业务核验成功。status: 1表示发票未作废(正常状态);2为作废,3为红冲。itemList为空数组时,表示该发票无商品明细(如定额发票)。
6.3 步骤追踪
- 准备发票图片 → 转为 Base64
- 构造 POST 请求 → 携带 APPCODE 鉴权头
- 发送请求 → 等待响应(通常 1~3 秒)
- 解析 JSON → 提取票面字段
- 业务逻辑处理 → 入库/填单/对账
七、接口调用限制与规范
| 项目 | 说明 |
|---|---|
| 协议 | HTTPS |
| 调用方式 | POST |
| 请求体格式 | application/x-www-form-urlencoded |
| 鉴权方式 | Authorization: APPCODE <appcode> |
| QPS 上限 | 以阿里云控制台实时配置为准 |
| 次数扣减规则 | HTTP 200 时扣减,非 200 不扣减 |
| 图片格式 | JPG / PNG / BMP 等常见格式 |
| 图片大小建议 | 压缩至 2MB 以内,避免超时 |
合规要求:发票图片属于敏感经营数据,传输请使用 HTTPS;日志中避免完整留存 Base64;核验结果仅用于业务校验,不作为唯一法律依据。
八、能力边界与免责声明
支持:增值税普通发票(电子)、增值税专用发票、机动车销售统一发票、增值税普通发票(纸质)等常见发票类型。
不支持:
- 非发票类票据(如收据、门票、通行证)
- 模糊、残缺、被遮挡的发票图片
- 已过税务机关核验期限的历史发票
免责声明:本接口核验结果基于税局公开数据,仅供参考。因税局数据同步延迟、图片识别误差等原因导致的核验偏差,不承担业务决策责任。
九、错误码与排查指南
网关层 HTTP 状态码
| 状态码 | 含义 | 排查办法 |
|---|---|---|
| 400 | 请求参数错误 | 检查是否传入 imgBase64 或 imgUrl |
| 401 | 身份校验失败 | 确认 APPCODE 有效且已授权该 API |
| 403 | 请求被禁止 | 查看控制台余量与有效期 |
| 404 | 路径错误 | 核对路径 /ocrCheckVAT |
| 500 | 服务端内部错误 | 稍后重试或联系平台 |
| 503 | 服务暂不可用 | 降低频率,稍后重试 |
业务层错误码
| ret_code | remark | 排查办法 |
|---|---|---|
| -1 | 查验不一致 | 票面信息与税局底账不一致,核对发票真伪 |
| -2 | 查无此票 | 发票未同步至税局系统或 OCR 识别错误 |
| -3 | 超过当日查验次数 | 单张发票当日查验已达上限,次日再试 |
| -4 | 查验不成功,请重试 | 服务商端超时,指数退避重试 2~3 次 |

十、常见问题 FAQ
Q1:imgBase64 和 imgUrl 可以同时传吗?
不建议。两者二选一,同时传入可能造成请求体过大,服务端以其中一个为准。
Q2:图片格式有要求吗?
支持 JPG、PNG、BMP 等常见格式。建议上传清晰、完整的发票图片。
Q3:HTTP 200 但 ret_code 不为 0 是否扣次数?
是。HTTP 200 即视为一次成功调用,无论业务结果如何均扣减次数。
Q4:如何降低调用成本?
对高频重复场景做短时缓存(键:发票代码_发票号码,TTL 5~15 分钟);批量处理前做参数校验与去重;设置客户端限流。
Q5:为什么返回"查无此票"?
可能原因:发票尚未同步至税局系统;图片模糊导致 OCR 识别错误;发票状态异常。建议核对图片清晰度与票面信息。
十一、内容小结
本文围绕增值税发票在线查验接口,介绍了适用场景、请求参数、返回结构、错误码排查与多语言接入示例。接入时需注意:
- imgBase64 与 imgUrl 二选一;
- 使用
Authorization: APPCODE <appcode>鉴权; - 完整调用地址、QPS 与收费规则以阿里云控制台为准;
- 对敏感发票图片与核验结果做好传输加密、日志脱敏与缓存控制;
- 失败时按指数退避重试,避免频繁触发限流。
合理运用重试、缓存与限流策略,可将该能力稳定集成到财务、报销或发票归档系统中。
