POST /apiv2/screening
为区块链地址订购 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 | 字符串 | 是 | 要筛查的地址,10–128 个字符 |
| network | 字符串 | 是 | 网络代码。每个服务商支持的代码由 GET /apiv2/screening/providers 列出 |
| provider | 字符串 | 是 | elliptic 或 bitok。没有默认值 |
| wait_for_result | 布尔值 | 否 | 为 true 时最多等待结果 15 秒。默认值为 false |
| language | 字符串 | 否 | 报告语言。仅支持 en |
未知字段将被拒绝。 包含不在上表中的字段的请求体将返回状态码 400 以及错误代码 4001。
provider 为必填项且无默认值。 您始终需要选择付费的服务商。
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 | 字符串 | 订单标识符,后续用于读取结果 |
| status | 字符串 | pending、processing、completed、skipped、failed |
| api_version | 字符串 | 创建该订单的契约版本 |
| cache_hit | 布尔值 | 当复用最近的结果且未扣费时为 true |
| created_at | 字符串 | RFC 3339 格式,UTC,微秒精度 |
| started_at | 字符串 | null | 调用服务商的开始时间。skipped 状态下为 null |
| completed_at | 字符串 | null | 结果返回的时间 |
| error | 字符串 | 仅适用于 failed:失败原因 |
| reason | 字符串 | 仅适用于 skipped:address_inactive |
所有时间戳均为 UTC 时间,RFC 3339 格式,带有 Z 后缀和微秒级精度。
billing
| 字段 | 类型 | 描述 |
|---|---|---|
| charged | 布尔值 | 是否已扣费 |
| price_usdt | 字符串 | 服务商以 USDT 计价的公开价格 |
| base_amount | 字符串 | 扣费币种的订单价格,不含子用户加价 |
| markup_amount | 字符串 | 子用户加价。直客账户为 "0" |
| charged_amount | 字符串 | 实际从余额中扣除的金额 |
| charged_currency | 字符串 | TRX |
| exchange_rate | 字符串 | null | 兑换所使用的汇率 |
| payment_status | 字符串 | paid、pending、failed、not_charged、postpaid |
检查成功后的短时间内,payment_status 为 pending:费用先被冻结,并在 1 小时内完成结算。failed 表示已退款。not_charged 表示从未产生扣费 — 比如复用了结果或跳过了地址。postpaid — 参见后付费账户。
precheck
在付费筛查之前,系统会检查该地址是否存在链上活动。没有任何活动的地址不会发送给服务商,也不会产生扣费。
| 字段 | 类型 | 描述 |
|---|---|---|
| activity_checked | 布尔值 | 是否执行了检查。在不存在该功能的网络上为 false |
| activity_status | 字符串 | active、inactive、unknown |
| source | 字符串 | null | 机制名称 |
unknown 不会阻止付费筛查:如果活动检测服务不可用,该地址将被视为活跃状态。
check
| 字段 | 类型 | 描述 |
|---|---|---|
| provider | 字符串 | 执行检查的服务商 |
| provider_check_id | 字符串 | null | 服务商自身的标识符 — 在与他们就结果产生争议时请提供此标识 |
| checked_at | 字符串 | null | 服务商生成结果的时间 |
| status | 字符串 | 参见下表 |
| provider_status | 字符串 | null | 服务商自身的原始描述,未经修改 |
order.status | check.status | 含义 |
|---|---|---|
pending | pending | 订单已接受,尚未开始 |
processing | running | 服务商正在处理中 |
completed | completed | 已收到结果 |
failed | failed | 在调用服务商之前或调用期间被拒绝 |
skipped | not_performed | 该地址无活动;从未调用服务商,未扣除任何费用 |
risk
| 字段 | 类型 | 描述 |
|---|---|---|
| score | 字符串 | null | 服务商自身的评分,以小数字符串形式返回 |
| scale | 对象 | 该服务商评分尺度的 min 和 max |
| level | 字符串 | none、low、medium、high、severe |
| level_source | 字符串 | computed — 我们根据评分推导出的等级;provider — 服务商直接给出的等级 |
| provider_level | 字符串 | null | 服务商自身使用的描述(若其有返回) |
| policy | 字符串 | 阈值策略名称,netts-risk-v1 |
| by_direction | 对象 | 按 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 地址为您生成一个密钥。它用于防止重复点击和网关重试,无法防止一分钟后的重复请求:后者属于全新的真实订单并将被扣费。
错误响应
应用程序引发的所有错误均采用 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 属于扩展字段:可据此编写错误处理匹配逻辑。额外字段取决于具体错误,在您未知的情况下必须忽略。
| 代码 | 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"} |
速率限制
每秒 5 次请求,每分钟 150 次请求,所有筛查接口路径共享此配额。
后付费账户
采用后付费结算的账户与其他用户使用完全相同的端点、URL、请求头和请求体。其区别仅在于检查费用的支付方式:
- 不会从您的充值押金中扣款。 每次完成检查的美元价格(例如 Elliptic 为 0.98 美元)将按照合同中约定的结算币种累加到您账户的应付款余额中。您只需根据协议按账单付款即可。
- 您的账户拥有一个信用额度。只要应付金额在额度范围内,即使充值押金为零也可以正常提交检查。
- 仅对已完成的检查计费。失败的检查、无活动的地址 (
skipped) 以及复用的最近结果均不产生费用。
后付费结算需向 Netts 申请开通。
后付费检查的 billing
"billing": {
"charged": false,
"price_usdt": "0.98",
"base_amount": "2.960725",
"markup_amount": "0",
"charged_amount": "2.960725",
"charged_currency": "TRX",
"exchange_rate": "0.33100000",
"payment_status": "postpaid"
}| 字段 | 描述 |
|---|---|
| charged | false:未从押金中扣费 |
| price_usdt | 检查的美元价格。此金额将累加到您的应付余额中 |
| charged_amount | 折合为 TRX 的相同价格,仅供参考 |
| payment_status | postpaid。若检查失败或被跳过则为 not_charged |
达到信用额度 (402)
{
"type": "https://doc.netts.io/api/v2/errors/credit-limit-reached",
"title": "Postpaid credit limit reached",
"status": 402,
"detail": "Postpaid credit limit reached.",
"instance": "/apiv2/screening",
"code": 1004,
"payment_mode": "postpaid",
"reason": "limit_reached"
}检查不会被订购,也不会产生任何计费。一旦您的还款到账或额度获得提升,即可重新接受新的检查请求。
后付费错误代码
| 代码 | HTTP | 描述 |
|---|---|---|
1004 | 402 | 已达到后付费信用额度 |
5032 | 503 | 价格暂时不可用 |
5034 | 503 | 计费服务暂时不可用 — 检查未被受理 |
5036 | 503 | 信用检查暂时不可用 — 请稍后重试 |
对于以上所有响应,均不会订购任何检查,也不会产生任何计费。
注意
- 定价: 每个服务商的单次检查价格固定,参见 GET /apiv2/screening/providers;按扣费时的汇率从 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包含的内容与服务商标记表达的含义