银行卡归属地查询的 cardNum 与 needBin 怎么传:什么时候才需要 BIN 与 Luhn 效验
银行卡归属地查询参数说明needBinisLuhnLuhn效验 # 银行卡归属地查询的 cardNum 与 needBin 怎么传:什么时候才需要 BIN 与 Luhn 效验
> 接口:银行卡归属地查询(apiCode=30)· 接入点:`30-7` · 计费:按次计费,5 厘/次,查询失败不计费 · 请求方式:GET / POST · 适用人群:已接入、准备调优参数的开发者 · 阅读时间:约 7 分钟
> 最后实测核对:2026-09-15
一句话结论:银行卡归属地查询接口只有两个业务参数,`cardNum` 必填,`needBin` 决定要不要多拿 BIN 码与银联 Luhn 效验结果——不开就少四个字段、响应更快,开就多四个字段、耗时略增。
## 参数表
| 参数 | 类型 | 必填 | 示例值 | 作用 |
|------|------|------|--------|------|
| `cardNum` | String | 是 | `6228480402564890018` | 要查询的银行卡号 |
| `needBin` | String | 否 | `1` | 是否需要返回银行卡 BIN 码信息和银联 Luhn 效验。`1` 需要,`0` 不需要,不传默认不返回 |
POST 表单场景下还有个 Header 参数:
| Header | 类型 | 必填 | 示例值 |
|------|------|------|--------|
| `content-type` | String | 否 | `application/x-www-form-urlencoded` |
鉴权参数 `appKey` 走 query,不在这两个业务参数里。
## cardNum 怎么传
`cardNum` 传卡号本身,不含空格和分隔符。2026-09-15 实测传 `6228480402564890018`(19 位)能正常返回,返回体里的 `cardNum` 与入参一致。
位数不是硬门槛,但查不到就没有结果。实测传一个 10 位数字 `1234567890`,返回:
```json
{
"showapi_res_code": 0,
"showapi_fee_num": 0,
"showapi_res_body": {
"remark": "找不到此卡号信息",
"ret_code": -1
}
}
```
`ret_code` 为 `-1`,`showapi_fee_num` 为 `0`。这次调用不计费,业务侧按「未查到」处理即可。
必须传。不传 `cardNum` 时请求不会被受理,返回的是外层错误:
```json
{
"showapi_res_error": "must input cardNum field",
"showapi_res_code": -1,
"showapi_fee_num": 0,
"showapi_res_body": {}
}
```
注意这时 `showapi_res_body` 是空对象,里面没有 `ret_code`。所以判定逻辑得先看外层,具体写法见[银行卡归属地查询排错:三种失败形态怎么区分](https://www.showapi.com/guides/bank-card-attribution-error-codes-30)。
## needBin 怎么传
`needBin` 控制四个字段是否返回:`card_bin`、`bin_digits`、`card_digits`、`isLuhn`。
传 `1` 时,四个字段都出现:
```json
{
"card_bin": "622848",
"bin_digits": "6",
"card_digits": "19",
"isLuhn": "1"
}
```
传 `0` 或不传时,四个字段整体不出现。2026-09-15 实测对比:同一张卡,不传 `needBin` 的返回体里完全没有这四个键;传 `needBin=1` 才出现。计费口径不变,两次都是 `showapi_fee_num: 1`。
接口文档对 `needBin=1` 的说明是「返回这些信息将使得查询更加耗时」。也就是说这四项是有代价的,不值得每次调用都开。
BIN 未收录时字段仍存在、值为空字符串:
```json
{
"card_bin": "",
"bin_digits": "",
"card_digits": "19",
"isLuhn": "0"
}
```
## isLuhn 的三个取值
`isLuhn` 不是布尔量,它有三个取值:
| 取值 | 含义 |
|------|------|
| `1` | 能通过中国银联 Luhn 效验 |
| `0` | 不能通过 |
| 空字符串 | 不支持效验 |
做卡号形态初筛时,只有 `1` 和 `0` 能给出明确判断;空字符串代表本卡号不参与这项校验,不能当成「不合法」处理。
## 什么场景该开 needBin
| 你要做的事 | 建议 |
|------|------|
| 只展示银行名、归属地、卡种、客服电话 | 不传 `needBin` |
| 绑卡时做卡号形态初筛(位数、BIN 段、Luhn) | 传 `needBin=1` |
| 批量核对存量卡号的开户行 | 不传 `needBin`,减少响应耗时 |
| 风控侧要拿卡号长度做异常识别 | 传 `needBin=1` |
一句话:`needBin` 只在「需要判断这张卡号本身是否形态合法」时才开。
## 三语言调用示例
Python:
```python
import requests
APPKEY = "YOUR_APPKEY"
API_URL = "https://route.showapi.com/30-7"
def query_bank_card(card_num: str, need_bin: bool = False, timeout: int = 30) -> dict:
params = {"appKey": APPKEY, "cardNum": card_num}
if need_bin:
params["needBin"] = "1"
resp = requests.post(API_URL, data=params, timeout=timeout,
headers={"content-type": "application/x-www-form-urlencoded"})
resp.raise_for_status()
data = resp.json()
if data.get("showapi_res_code") != 0:
raise RuntimeError(f'请求失败:{data.get("showapi_res_error")}')
body = data.get("showapi_res_body") or {}
if str(body.get("ret_code")) != "0":
return {"ok": False, "reason": body.get("remark") or "未查到归属地", "raw": body}
return {
"ok": True,
"area": body.get("area", ""),
"bank": body.get("formatBankName") or body.get("bankName", ""),
"brand": body.get("brand", ""),
"card_type": body.get("cardType", ""),
# 只有 needBin=1 时才有值,其余情况走默认值
"card_bin": body.get("card_bin", ""),
"is_luhn": body.get("isLuhn", ""),
}
```
cURL(POST 表单):
```bash
curl -s -X POST "https://route.showapi.com/30-7?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded" \
-d "cardNum=6228480402564890018&needBin=1" \
--max-time 30
```
Node.js:
```javascript
const APPKEY = "YOUR_APPKEY";
const API_URL = "https://route.showapi.com/30-7";
async function queryBankCard(cardNum, needBin = false) {
const body = new URLSearchParams({ cardNum });
if (needBin) body.set("needBin", "1");
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 30000);
try {
const res = await fetch(`${API_URL}?appKey=${encodeURIComponent(APPKEY)}`, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body,
signal: controller.signal,
});
const data = await res.json();
if (data.showapi_res_code !== 0) throw new Error(`请求失败:${data.showapi_res_error}`);
const b = data.showapi_res_body || {};
if (String(b.ret_code) !== "0") return { ok: false, reason: b.remark || "未查到归属地" };
return {
ok: true,
area: b.area || "",
bank: b.formatBankName || b.bankName || "",
brand: b.brand || "",
cardType: b.cardType || "",
cardBin: b.card_bin || "",
isLuhn: b.isLuhn || "",
};
} finally {
clearTimeout(timer);
}
}
```
## FAQ
**Q1:`needBin` 会不会影响结果里其他字段?**
不会。2026-09-15 实测对比同一张卡号的两次调用,`area`、`bankName`、`formatBankName`、`brand`、`cardType`、`tel`、`url`、`logo`、`simpleCode` 的取值完全一致,只有 BIN 相关的四个字段出现与否不同,计费次数也都是 `1`。
**Q2:`needBin` 传 `0` 和完全不传有区别吗?**
没有区别,两种写法都不返回那四个字段。文档对 `needBin` 的说明是「`1` 表示需要,`0` 表示不需要,默认不会返回这些信息」。
**Q3:卡号里带空格或「-」能查吗?**
接口按传入的字符串处理,建议在调用前先去空格、去分隔符,只传纯数字串。
**Q4:`cardNum` 位数不对会返回什么?**
看具体情况:位数明显不足且 BIN 无法识别的,会走「卡号未收录」这条路,返回 `ret_code: -1` 与 `remark`;这种失败不计费。
**Q5:POST 和 GET 用哪个?**
两者都支持。参数只有两个,GET 更省事;如果你不想让卡号出现在访问日志的 URL 里,用 POST 表单,参数放 body。
## 下一步阅读
- [银行卡归属地查询返回字段逐个说清](https://www.showapi.com/guides/bank-card-attribution-response-fields-30)——看清 `needBin` 控制的是哪四个字段
- [银行卡归属地查询排错:三种失败形态怎么区分](https://www.showapi.com/guides/bank-card-attribution-error-codes-30)——缺 `cardNum` 时的返回形态
- [银行卡归属地查询按次计费下怎么省调用](https://www.showapi.com/guides/bank-card-attribution-cache-cost-30)——BIN 前缀缓存的具体设计
- **本系列共 10 篇**:查看[银行卡归属地查询指南总目录](https://www.showapi.com/guides/bank-card-attribution-guides-30)