POST /apiv2/screening
为区块链地址创建反洗钱(AML)筛查订单。这是版本 2 协议:针对每个提供商和订单的每种状态提供统一的响应结构、以字符串形式表示的小数,以及单一的错误格式。
它取代了 POST /apiv2/aml,后者仍可继续使用,且在未发出通知前不会停用。
端点 URL
POST https://netts.io/apiv2/screening请求头
| 请求头 | 必填 | 说明 |
|---|---|---|
| Content-Type | 是 | application/json |
| X-API-KEY | 是 | 来自 Netts 控制台的 API 密钥 |
| X-Idempotency-Key | 否 | 用于安全重试的自定义密钥。参见幂等性 |
请求体
{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait_for_result": true
}请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| address | string | 是 | 待筛查地址,10–128 个字符 |
| network | string | 是 | 网络代号。每个提供商支持的代号由 GET /apiv2/screening/providers 列出;包含其名称的完整网络列表在此处 |
| provider | string | 是 | elliptic 或 bitok。无默认值 |
| wait_for_result | boolean | 否 | true 表示最多等待结果 15 秒。默认值为 false |
| language | string | 否 | 报告语言。仅支持 en |
拒绝未知字段。 包含上述表格中未列出字段的请求体将返回 400,错误代码为 4001。在版本 1 中,未知字段会被静默忽略,而拼写错误的 wait 意味着调用方在等待一个永远不会同步返回的结果。
provider 为必填项且无默认值。 在版本 1 中,省略提供商默认代表 Elliptic,因此未做选择的调用方会为他们从未指定的提供商付费。
provider 在模式定义中是自由格式字符串,而非枚举。 目前接受两个值;引入第三个提供商绝不能对任何根据模式验证响应的用户造成破坏性变更。当前列表、每个提供商覆盖的网络以及各自评分的量表来自 GET /apiv2/screening/providers。
请求示例
cURL — 等待结果
curl -X POST https://netts.io/apiv2/screening \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-d '{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait_for_result": true
}'cURL — 接受并轮询
curl -X POST https://netts.io/apiv2/screening \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-d '{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "bitok"
}'响应为 202 Accepted,带有指向该订单的 Location 头。
Python
import requests
from decimal import Decimal
url = "https://netts.io/apiv2/screening"
headers = {
"Content-Type": "application/json",
"X-API-KEY": "your_api_key",
}
payload = {
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait_for_result": True,
}
response = requests.post(url, headers=headers, json=payload)
if response.status_code in (200, 202):
body = response.json()
print("Order:", body["order"]["client_order_id"])
print("Status:", body["order"]["status"])
if body["risk"]["score"] is not None:
# Parse provider numbers as Decimal, never as float
print("Score:", Decimal(body["risk"]["score"]), "of", body["risk"]["scale"]["max"])
print("Level:", body["risk"]["level"], "-", body["risk"]["level_source"])
print("Charged:", body["billing"]["charged_amount"], body["billing"]["charged_currency"])
else:
problem = response.json()
print(problem["code"], problem["title"], "-", problem["detail"])响应码
| 场景 | 状态码 | 响应头 |
|---|---|---|
| 订单已创建,筛查在后台运行 | 202 Accepted | Location: /apiv2/screening/{client_order_id} |
结果包含在响应中(wait_for_result) | 200 OK | — |
| 复用近期的检查结果,不收取费用 | 200 OK | — |
| 地址无区块链活动,不收取费用 | 200 OK | — |
| 错误 | 参见错误响应 | Content-Type: application/problem+json |
带有筛查结果的响应在发送时会附带 Cache-Control: private, no-store。
响应
{
"schema_version": 2,
"order": {
"client_order_id": "A90D21F68C9AEA2",
"status": "completed",
"api_version": "v2",
"cache_hit": false,
"created_at": "2026-09-13T08:14:29.614988Z",
"started_at": "2026-09-13T08:14:30.288251Z",
"completed_at": "2026-09-13T08:14:34.993174Z"
},
"request": {
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic"
},
"billing": {
"charged": true,
"price_usdt": "0.98",
"base_amount": "2.882421",
"markup_amount": "0",
"charged_amount": "2.882421",
"charged_currency": "TRX",
"exchange_rate": "0.33999200",
"payment_status": "pending"
},
"precheck": {
"activity_checked": true,
"activity_status": "active",
"source": "tron-address-checker"
},
"check": {
"provider": "elliptic",
"provider_check_id": "b4903a5d-9f22-4075-b51b-beb40b419b97",
"checked_at": "2026-09-13T08:14:32.144000Z",
"status": "completed",
"provider_status": "complete"
},
"risk": {
"score": "0.9634087310611608",
"scale": { "min": 0, "max": 10 },
"level": "low",
"level_source": "computed",
"provider_level": null,
"policy": "netts-risk-v1",
"by_direction": {
"source": "0.12332156899576921",
"destination": "0.9634087310611608"
}
},
"sanctions": {
"self": false,
"self_entities": null,
"exposure": {
"entity": "HTX (formerly Huobi) - Post-Sanctions - UK Sanctions List - 26 May 2026",
"category": "Exchange",
"share_fraction": "0.004409451392423414",
"proximity": "indirect",
"hops": 3,
"direction": "source",
"rule_name": "Sanctioned, TF & CSAM"
},
"items": []
},
"exposure": [
{
"category": "Exchange",
"share_fraction": "0.1888065152442461",
"direction": "source",
"hops": 2,
"is_screened_address": false,
"entities": [
{ "name": "Binance", "category": "Exchange", "is_vasp": true,
"is_primary": true, "is_after_sanction_date": null }
]
}
],
"rules": [
{ "name": "Sanctioned, TF & CSAM", "type": "exposure", "level": null,
"score": "0.061426483114820525", "share_fraction": null, "category": null,
"proximity": null, "direction": "source", "detected_at": null }
],
"entities": [
{ "name": "Unknown", "category": "Unknown", "is_vasp": null,
"is_primary": true, "is_after_sanction_date": false }
],
"primary_entity": {
"name": "Unknown", "category": "Unknown", "is_vasp": null,
"is_primary": true, "is_after_sanction_date": false
},
"sanctioned_entities": [],
"wallet": {
"inflow_usd": "354663.6116669158",
"outflow_usd": "80248.63081808022"
},
"provider_data": { }
}字段集永不改变
无论提供商是谁,也无论订单处于何种状态,上面列出的每个块都会出现在每个响应中。提供商未提供的内容为 null;空列表为 [],而非 null;尚未包含数据的块会被填充 null 而不会被省略。一个解析器即可同时处理刚被接受的检查以及已完成的同一检查。
这对您的代码有两个影响:
- 忽略您无法识别的字段。 这些块中添加新字段无需发布新版本。拒绝未知字段属于您的代码缺陷,而非我们的问题;
provider_data不属于协议保证的一部分。 它的结构遵循提供商的定义,并且会随着提供商的变更而变更。协议所保证的所有内容都存在于上述的各个块中。
order
| 字段 | 类型 | 说明 |
|---|---|---|
| client_order_id | string | 订单标识符,后续用于读取结果 |
| status | string | pending、processing、completed、skipped、failed |
| api_version | string | 创建该订单的协议版本 |
| cache_hit | boolean | 当复用近期结果且未收取任何费用时为 true |
| created_at | string | RFC 3339、UTC、微秒精度 |
| started_at | string | null | 向提供商发起调用的时间。针对 skipped 为 null |
| completed_at | string | null | 结果返回的时间 |
| error | string | 仅适用于 failed:失败原因 |
| reason | string | 仅适用于 skipped:address_inactive |
所有时间戳均为 UTC、RFC 3339 格式,带有 Z 后缀和微秒精度。
billing
| 字段 | 类型 | 说明 |
|---|---|---|
| charged | boolean | 是否已扣费 |
| price_usdt | string | 提供商以 USDT 计价的标价 |
| base_amount | string | 以扣费币种计价的订单价格,不含子用户加价 |
| markup_amount | string | 子用户加价。直接账户为 "0" |
| charged_amount | string | 从余额中实际扣除的金额 |
| charged_currency | string | TRX |
| exchange_rate | string | null | 用于折算的汇率 |
| payment_status | string | paid、pending、failed、not_charged |
检查成功后的短时间内,payment_status 为 pending:费用会先被预扣,并在一个小时内完成结算。failed 表示款项已退回。not_charged 表示从未产生扣费 — 例如复用结果或跳过的地址。
precheck
在执行付费筛查之前,系统会检查该地址是否存在区块链活动。无活动的地址不会发送给提供商,也不会被收费。
| 字段 | 类型 | 说明 |
|---|---|---|
| activity_checked | boolean | 是否执行了检查。在不存在该功能的网络上为 false |
| activity_status | string | active、inactive、unknown |
| source | string | null | 检查机制的名称 |
unknown 不会阻止付费筛查:如果活动检查服务不可用,该地址将被视为活跃状态。
check
| 字段 | 类型 | 说明 |
|---|---|---|
| provider | string | 执行检查的提供商 |
| provider_check_id | string | null | 提供商自身的标识符 — 在与他们对结果提出争议时请引用此标识 |
| checked_at | string | null | 提供商生成结果的时间 |
| status | string | 参见下表 |
| provider_status | string | null | 提供商自有的原始状态描述,未经修改 |
order.status | check.status | 含义 |
|---|---|---|
pending | pending | 订单已接受,尚未开始 |
processing | running | 提供商正在处理中 |
completed | completed | 已收到结果 |
failed | failed | 在调用提供商之前或期间被拒绝 |
skipped | not_performed | 该地址无活动;从未调用提供商且未扣除任何费用 |
risk
| 字段 | 类型 | 说明 |
|---|---|---|
| score | string | null | 提供商自有的评分,以小数字符串表示 |
| scale | object | 该提供商量表的 min 和 max |
| level | string | none、low、medium、high、severe |
| level_source | string | computed — 我们根据评分推导出的等级;provider — 提供商直接声明的等级 |
| provider_level | string | null | 提供商自有的评级词汇(当其返回时) |
| policy | string | 阈值策略名称,netts-risk-v1 |
| by_direction | object | 细分为 source 和 destination 的评分(当提供商对其进行拆分时) |
评分绝不会重新换算缩放。 Elliptic 的范围为 0–10,而 BitOK 为 0–1,在一个量表上的 7 在任何实际意义上都不等于另一个量表上的 0.7。响应中会包含量表范围,以确保针对某一个提供商编写的集成不会在仅变更配置后误读另一个提供商的分数。
等级在整个 API 中采用统一词汇。 当提供商声明了自己的等级时,我们会直接传递该值并在 level_source 中予以说明;当提供商未提供时,我们使用 netts-risk-v1 阈值从评分中推导出等级并作相应说明。同一检查在 API 响应、控制台以及 PDF 报告中会显示完全相同的词汇。
exposure[]、rules[]、entities[]
exposure[] 按交易对手类别细分资金。rules[] 列出被触发的提供商规则。entities[] 列出地址本身所属的实体;primary_entity 依据固定规则从中选取一个 — 优先选取提供商标记为主要的实体,其次为第一个实体,否则为 null。sanctioned_entities[] 包含 entities[] 中在制裁生效日期后被标记为活跃的实体。
份额以小数表示,绝非百分比
响应中的每个份额都是单一字段 share_fraction,即介于 "0" 与 "1" 之间的小数字符串。
Elliptic 报告 31.574732212596924 % -> "share_fraction": "0.31574732212596924"
BitOK 报告 0.8488 -> "share_fraction": "0.8488"各提供商在单位上并不一致:相同的三分之一风险敞口,一家返回 31.57,另一家返回 0.3157。如果用一个字段同时承载这两种单位,在不清楚具体提供商的情况下将无法进行解析。提供商以其自身单位提供的原始数值将保留在 provider_data 中。
数字均表示为字符串
来自提供商的所有数字 — 评分、份额、美元交易量以及 billing 中的所有金额 — 均为小数字符串。
"score": "0.9634087310611608"在 JavaScript、Go 或任何使用二进制浮点数的语言中将其解析为 JSON 数字会导致精度近似,并且您打印出的值将不再与提供商发布的值一致。请使用高精度小数类型解析这些字段:Python 中使用 Decimal,Java 中使用 BigDecimal,JavaScript 中使用 decimal.Decimal 或保持为字符串。
属于我们自身而非提供商的字段 — 如 scale.min、scale.max、hops — 则是普通的 JSON 数字。
复用近期结果
当您在 60 秒内再次筛查相同的地址、网络和提供商时,系统将返回较早的结果且不收取任何费用。
每个请求仍会创建自己的订单并拥有独立的 client_order_id;被复用的订单会被标记为 "cache_hit": true,且其 billing 块报告 "charged": false 和 "payment_status": "not_charged"。结果所来源订单的标识符不会公开 — 它可能属于另一个账户。
复用仅在单个账户内发生。绝不会向您返回其他人筛查过的结果。
幂等性
发送带有自定义值的 X-Idempotency-Key 可确保安全重试:带有相同请求体的相同密钥将返回存储的响应,而不会创建第二次检查。
| 场景 | 状态码 | 响应 |
|---|---|---|
| 带有此密钥的第一个请求仍在运行 | 409 | 4090 |
| 相同的密钥,但请求体不同 | 409 | 4093 |
| 相同的密钥,相同的请求体,已处理完成 | 存储的状态码 | 存储的响应 |
如果您未发送该头,系统将在两秒窗口期内根据 API 密钥、地址、提供商和您的 IP 地址自动生成一个密钥。它能够防范双击提交和网关重试,但无法防范一分钟后的重复请求:后者会被视为全新的订单并进行收费。
密钥的作用域按端点划分。 发送到 POST /apiv2/aml 和发送到当前端点的相同值代表针对两个不同请求的两次独立保证 — 它们的请求体不同,响应也不同。在将集成从版本 1 迁移到版本 2 时复用您的密钥是安全的:它既不会向您返回版本 1 的响应,也不会被视为对不同请求体使用了相同密钥。
错误响应
应用程序引发的每个错误均采用 RFC 9457 规范,并带有 Content-Type: application/problem+json:
{
"type": "https://doc.netts.io/api/v2/errors/insufficient-funds",
"title": "Insufficient funds",
"status": 403,
"detail": "Insufficient funds. Required: 2.888742 TRX, Available: 1.203000 TRX",
"instance": "/apiv2/screening",
"code": 1004,
"required_trx": "2.888742",
"available_trx": "1.203000"
}type、title、status、detail 和 instance 是标准字段。保留数字形式的 code 作为扩展字段,以便针对版本 1 编写的集成可以继续对其进行匹配。附加字段取决于具体错误,当您无法识别时必须予以忽略。
| 错误代码 | HTTP | 含义 |
|---|---|---|
4000 | 400 | 请求体不是有效的 JSON |
4001 | 400 | 字段验证失败,或发送了未知字段 |
4002 | 403 | 该提供商对您的账户不可用 |
4003 | 400 | 订单标识符格式错误 |
4004 | 400 | 提供商不支持所请求的网络 |
4010 | 401 | 无 API 密钥 |
4011 | 401 | API 密钥或 IP 地址未被接受 |
4040 | 404 | 订单未找到 |
4041 | 404 | 账户未找到 |
4090 | 409 | 带有此幂等密钥的请求仍在运行 |
4091 | 409 | 重复请求 |
4093 | 409 | 此幂等密钥已被用于不同的请求体 |
1004 | 403 | 余额不足 |
5000 | 500 | 内部错误 |
5001 | 500 | 扣费未成功 |
5002 | 500 | 订单未创建 |
5030 | 503 | 提供商不可用 |
不使用此格式的错误
某些故障发生在网关层(尚未到达应用程序),它们会保留网关自有的格式。请将任何 Content-Type 不是 application/problem+json 的响应视为以下情况之一:
| 场景 | HTTP | 响应体 |
|---|---|---|
| 无 API 密钥,或密钥未被接受 | 401 | {"detail":{"code":-1,"msg":"Invalid or missing API key"}} |
| 超出速率限制 | 429 | {"message":"API rate limit exceeded"} |
| 未知路径,或该路由不提供的方法 | 404 / 405 | {"detail":"Method Not Allowed"} |
速率限制
该限制与 POST /apiv2/aml 及其他 AML 路径共享:每秒 5 个请求,每分钟 150 个请求。迁移到此端点并不会为您提供额外的配额。
说明
- 计费:Elliptic 每次检查 $0.98,BitOK 每次检查 $0.50,根据扣费时的即时汇率从 TRX 余额中扣除。
- 处理时间:大多数检查在几秒钟内完成;具有冗长历史记录的地址可能需要长达三分钟。请使用异步模式并通过 GET /apiv2/screening/{client_order_id} 读取结果。
- 非活跃地址返回
skipped且不予计费。 - 绝不返回原始的提供商响应。
provider_data是经过审查的映射数据;属于我们在提供商处账户而非属于被筛查地址的字段绝不会公开给任何人。
报告
该端点仅返回 JSON。不提供 PDF 或 Markdown。
构成报告所需的所有内容已全部包含在响应中:统一的数据块和 provider_data。由您在本地自行渲染即可得到您真正需要的文档 — 包含您的品牌形象、您的语言、您的排版布局 — 如果您转售检查服务,这一点尤为关键,因为附带我们名称的报告不适合交付给您自己的客户。
如果您需要将报告作为提供给第三方(银行、监管机构、交易对手)的凭证,请注意:无论由谁生成,未签名的 PDF 都不具备凭据效力,任何人在文本编辑器中一分钟内即可完成篡改。可验证的凭据需要数字签名或公开验证页面,这属于另一项独立功能。如果您有此需求,请告知我们您的交易对手的具体要求。
在 Netts 控制台中确实提供了针对相同检查的人类可读 PDF 报告,支持 17 种语言。
另请参阅
- GET /apiv2/screening/{client_order_id} — 读取检查结果
- GET /apiv2/screening/history — 您的检查历史,基于游标分页
- GET /apiv2/screening/providers — 提供商、价格、网络及量表
- GET /apiv2/screening/price — 单个提供商的价格
- AML 结果中的制裁信息 —
sanctions的含义以及提供商标志的含义