POST /apiv2/screening
Solicite una verificación AML para una dirección de blockchain: un único formato de respuesta para cada proveedor y cada estado de la orden, números decimales como cadenas y un formato de error único.
URL del endpoint
POST https://netts.io/apiv2/screeningEncabezados de solicitud
| Encabezado | Requerido | Descripción |
|---|---|---|
| Content-Type | Sí | application/json |
| X-API-KEY | Sí | Su clave API del panel de Netts |
| X-Idempotency-Key | No | Su propia clave para reintentos seguros. Consulte Idempotencia |
Cuerpo de solicitud
{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait_for_result": true
}Parámetros
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
| address | string | Sí | Dirección a verificar, de 10 a 128 caracteres |
| network | string | Sí | Ticker de la red. Los tickers que cubre cada proveedor se detallan en GET /apiv2/screening/providers |
| provider | string | Sí | elliptic o bitok. No hay un valor predeterminado |
| wait_for_result | boolean | No | true espera el resultado hasta por 15 segundos. Predeterminado false |
| language | string | No | Idioma del informe. Solo en |
Se rechazan los campos desconocidos. Un cuerpo que contenga un campo que no figure en la tabla anterior devuelve 400 con el código 4001.
provider es obligatorio y no tiene un valor predeterminado. Siempre elige el proveedor por el que paga.
provider es una cadena libre en el esquema, no una enumeración. Hoy se aceptan dos valores; un tercer proveedor no debe suponer un cambio disruptivo para nadie que valide las respuestas frente al esquema. La lista actual, las redes que cubre cada proveedor y la escala en la que puntúa cada uno proceden de GET /apiv2/screening/providers.
Ejemplos de Solicitudes
cURL — esperar el resultado
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 — aceptar y sondear
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"
}'La respuesta es 202 Accepted con un encabezado Location que apunta a la orden.
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"])Códigos de Respuesta
| Situación | Código | Encabezados |
|---|---|---|
| Orden creada, la verificación se ejecuta en segundo plano | 202 Accepted | Location: /apiv2/screening/{client_order_id} |
El resultado está en la respuesta (wait_for_result) | 200 OK | — |
| Resultado reutilizado de una verificación reciente, no se cobra nada | 200 OK | — |
| La dirección no tiene actividad en la blockchain, no se cobra nada | 200 OK | — |
| Error | ver Errores | Content-Type: application/problem+json |
Las respuestas que contienen un resultado de verificación se envían con Cache-Control: private, no-store.
Respuesta
{
"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": { }
}El conjunto de campos nunca cambia
Cada bloque listado anteriormente está presente en cada respuesta, sin importar el proveedor ni el estado de la orden. Lo que un proveedor no proporciona es null; una lista que no tiene elementos es [], no null; un bloque que aún no tiene datos se rellena con valores nulos en lugar de omitirse. Un único analizador procesa una verificación que acaba de ser aceptada y la misma verificación una vez finalizada.
Dos consecuencias para su código:
- ignore los campos que no conozca. Se añaden nuevos campos a estos bloques sin una nueva versión. Rechazar un campo desconocido es un error de su parte, no de la nuestra;
provider_datano forma parte del contrato. Su estructura sigue al proveedor y cambia cuando el proveedor cambia. Todo lo que el contrato garantiza reside en los bloques anteriores.
order
| Campo | Tipo | Descripción |
|---|---|---|
| client_order_id | string | Identificador de la orden, utilizado para consultar el resultado más adelante |
| status | string | pending, processing, completed, skipped, failed |
| api_version | string | Contrato que creó la orden |
| cache_hit | boolean | true cuando se reutilizó un resultado reciente y no se cobró nada |
| created_at | string | RFC 3339, UTC, microsegundos |
| started_at | string | null | Momento en el que se inició la llamada al proveedor. null para skipped |
| completed_at | string | null | Momento en el que llegó el resultado |
| error | string | Solo para failed: motivo por el que falló |
| reason | string | Solo para skipped: address_inactive |
Todas las marcas de tiempo están en UTC, RFC 3339, con sufijo Z y precisión de microsegundos.
billing
| Campo | Tipo | Descripción |
|---|---|---|
| charged | boolean | Si se debitó dinero |
| price_usdt | string | Precio de lista del proveedor en USDT |
| base_amount | string | Precio de la orden en la moneda cobrada, sin el margen de subusuario |
| markup_amount | string | Margen del subusuario. "0" para una cuenta directa |
| charged_amount | string | Lo que realmente se debitó del saldo |
| charged_currency | string | TRX |
| exchange_rate | string | null | Tasa de cambio utilizada para la conversión |
| payment_status | string | paid, pending, failed, not_charged, postpaid |
payment_status es pending durante un breve período tras una verificación exitosa: primero se retiene el cobro y se liquida en el transcurso de una hora. failed significa que el dinero fue devuelto. not_charged significa que nunca se generó un cobro: un resultado reutilizado o una dirección omitida. postpaid — consulte Cuentas Pospago.
precheck
Antes de una verificación de pago, se comprueba la actividad de la dirección en la blockchain. Una dirección sin actividad no se envía al proveedor y no se cobra.
| Campo | Tipo | Descripción |
|---|---|---|
| activity_checked | boolean | Si la comprobación se ejecutó. false en redes donde no existe |
| activity_status | string | active, inactive, unknown |
| source | string | null | Nombre del mecanismo |
unknown no detiene la verificación de pago: si el servicio de actividad no está disponible, la dirección se considera activa.
check
| Campo | Tipo | Descripción |
|---|---|---|
| provider | string | Proveedor que realizó la verificación |
| provider_check_id | string | null | El identificador propio del proveedor; indíquelo al disputar un resultado con ellos |
| checked_at | string | null | Momento en el que el proveedor generó el resultado |
| status | string | Consulte la tabla a continuación |
| provider_status | string | null | La formulación propia del proveedor, sin modificaciones |
order.status | check.status | Significado |
|---|---|---|
pending | pending | Orden aceptada, aún no iniciada |
processing | running | El proveedor está trabajando en ello |
completed | completed | Resultado recibido |
failed | failed | Rechazada antes o durante la llamada al proveedor |
skipped | not_performed | La dirección no tiene actividad; nunca se llamó al proveedor y no se cobró nada |
risk
| Campo | Tipo | Descripción |
|---|---|---|
| score | string | null | La puntuación propia del proveedor, como una cadena decimal |
| scale | object | min y max de la escala de ese proveedor |
| level | string | none, low, medium, high, severe |
| level_source | string | computed — derivamos el nivel a partir de la puntuación; provider — el proveedor lo indicó |
| provider_level | string | null | La palabra propia del proveedor, cuando devuelve una |
| policy | string | Nombre de la directiva de umbrales, netts-risk-v1 |
| by_direction | object | Puntuación desglosada en source y destination, cuando el proveedor la divide |
La puntuación nunca se reescala. Elliptic opera de 0 a 10 y BitOK opera de 0 a 1, y 7 en una escala no es 0.7 en la otra en ningún sentido práctico. La escala se incluye en la respuesta para que una integración desarrollada para un proveedor no interprete erróneamente a otro tras un simple cambio de configuración.
El nivel es un vocabulario único en toda la API. Cuando el proveedor indica un nivel propio, lo transferimos tal cual y lo indicamos en level_source; cuando no lo hace, derivamos el nivel a partir de la puntuación mediante los umbrales de netts-risk-v1 y reflejamos eso. Se muestra la misma palabra en la respuesta de la API, en el panel y en el informe en PDF para una misma verificación.
exposure[], rules[], entities[]
exposure[] desglosa los fondos por categoría de contraparte. rules[] enumera las reglas del proveedor que se activaron. entities[] enumera las entidades a las que pertenece la dirección en sí; primary_entity elige una de ellas según una regla fija: la entidad que el proveedor marcó como principal, en su defecto la primera, o en su defecto null. sanctioned_entities[] contiene aquellas de entities[] marcadas como activas después de una fecha de sanciones.
Las participaciones son fracciones, nunca porcentajes
Cada participación en la respuesta es un campo único, share_fraction, una cadena decimal entre "0" y "1".
Elliptic informa 31.574732212596924 % -> "share_fraction": "0.31574732212596924"
BitOK informa 0.8488 -> "share_fraction": "0.8488"Los proveedores difieren en las unidades: un mismo tercio de exposición llega como 31.57 desde uno y como 0.3157 desde el otro. Un solo campo que contuviera ambos formatos sería imposible de interpretar sin saber qué proveedor se utilizó. El valor original del proveedor en sus propias unidades permanece en provider_data.
Los números son cadenas
Cada número procedente de un proveedor —puntuaciones, participaciones, volúmenes en USD y cada importe en billing— es una cadena decimal.
"score": "0.9634087310611608"Analizarlo como un número JSON en JavaScript, Go o cualquier otro lenguaje con punto flotante binario devuelve una aproximación, y el valor impreso deja de coincidir con el valor emitido por el proveedor. Procese estos campos con un tipo decimal: Decimal en Python, BigDecimal en Java, decimal.Decimal o una cadena en JavaScript.
Los campos que son nuestros y no del proveedor —scale.min, scale.max, hops— son números JSON simples.
Reutilización de un resultado reciente
Cuando vuelve a verificar la misma dirección, red y proveedor dentro de un lapso de 60 segundos, se devuelve el resultado anterior y no se cobra nada.
Cada solicitud sigue creando su propia orden con su respectivo client_order_id; la reutilizada se marca con "cache_hit": true y su bloque billing reporta "charged": false con "payment_status": "not_charged". No se divulga el identificador de la orden de la que proviene el resultado; este podría pertenecer a otra cuenta.
La reutilización solo ocurre dentro de una misma cuenta. Nunca se le devolverá un resultado verificado por otra persona.
Idempotencia
Envíe X-Idempotency-Key con un valor propio para que un reintento sea seguro: la misma clave con el mismo cuerpo devuelve la respuesta almacenada en lugar de solicitar una segunda verificación.
| Situación | Código | Respuesta |
|---|---|---|
| La primera solicitud con esta clave aún se está ejecutando | 409 | 4090 |
| La misma clave, un cuerpo de solicitud diferente | 409 | 4093 |
| La misma clave, el mismo cuerpo, ya finalizada | el código almacenado | la respuesta almacenada |
Si no envía el encabezado, se genera una clave para usted a partir de la clave API, la dirección, el proveedor y su dirección IP, dentro de una ventana de dos segundos. Esto protege contra un doble clic y un reintento de la pasarela, no contra una repetición un minuto más tarde: esa última se considera una nueva orden legítima y se cobra.
Errores
Cada error generado por la aplicación utiliza RFC 9457 con 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 e instance son los campos estándar. El code numérico es una extensión: base su gestión de errores en él. Los campos adicionales dependen del error y deben ignorarse si no los conoce.
| Código | HTTP | Significado |
|---|---|---|
4000 | 400 | El cuerpo no es un JSON válido |
4001 | 400 | Un campo no superó la validación o se envió un campo desconocido |
4002 | 403 | El proveedor no está disponible para su cuenta |
4003 | 400 | Identificador de orden con formato incorrecto |
4004 | 400 | El proveedor no admite la red solicitada |
4010 | 401 | Sin clave API |
4011 | 401 | Clave API o dirección IP no aceptada |
4040 | 404 | Orden no encontrada |
4041 | 404 | Cuenta no encontrada |
4090 | 409 | Una solicitud con esta clave de idempotencia aún se está ejecutando |
4091 | 409 | Solicitud duplicada |
4093 | 409 | Esta clave de idempotencia se utilizó con un cuerpo diferente |
1004 | 403 | Saldo insuficiente |
5000 | 500 | Error interno |
5001 | 500 | El cobro no se completó |
5002 | 500 | No se creó la orden |
5030 | 503 | El proveedor no está disponible |
Errores que no utilizan este formato
Algunos fallos ocurren en la pasarela de enlace, antes de llegar a la aplicación, y conservan la estructura propia de dicha pasarela. Trate cualquier respuesta cuyo Content-Type no sea application/problem+json como uno de estos casos:
| Situación | HTTP | Cuerpo |
|---|---|---|
| Sin clave API, o una clave que no es aceptada | 401 | {"detail":{"code":-1,"msg":"Invalid or missing API key"}} |
| Límite de tasa excedido | 429 | {"message":"API rate limit exceeded"} |
| Ruta desconocida, o un método que la ruta no admite | 404 / 405 | {"detail":"Method Not Allowed"} |
Límites de Tasa
5 solicitudes por segundo y 150 por minuto, compartidas entre todas las rutas de verificación.
Cuentas Pospago
Las cuentas con facturación pospago utilizan el mismo endpoint, URL, encabezados y cuerpo de solicitud que todos los demás. La diferencia radica en cómo se paga la verificación:
- No se deduce nada de su depósito. El precio de cada verificación completada en dólares estadounidenses (por ejemplo, $0.98 para Elliptic) se añade al saldo pendiente de su cuenta en la moneda de liquidación acordada en su contrato. Usted lo paga mediante factura, según su acuerdo.
- Su cuenta tiene un límite de crédito. Mientras el importe adeudado se mantenga dentro del límite, las comprobaciones se aceptan incluso con un depósito de cero.
- Solo se facturan las comprobaciones completadas. Una comprobación que falló, una dirección sin actividad (
skipped) y un resultado reciente reutilizado no tienen ningún coste.
NETTS habilita la facturación pospago para una cuenta previa solicitud.
billing de una verificación pospago
"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"
}| Campo | Descripción |
|---|---|
| charged | false: no se debita nada del depósito |
| price_usdt | Precio de la verificación en dólares estadounidenses. Este es el importe añadido a su saldo pendiente |
| charged_amount | El mismo precio en TRX, como referencia |
| payment_status | postpaid. Para una verificación fallida u omitida — not_charged |
Límite de crédito alcanzado (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"
}La verificación no se solicita y no se factura nada. Se vuelven a aceptar nuevas comprobaciones una vez que se registra su pago o se amplía su límite.
Códigos de error pospago
| Código | HTTP | Descripción |
|---|---|---|
1004 | 402 | Límite de crédito pospago alcanzado |
5032 | 503 | Precio no disponible temporalmente |
5034 | 503 | Facturación no disponible temporalmente — no se aceptó la verificación |
5036 | 503 | Comprobación de crédito no disponible temporalmente — reintente más tarde |
En todas las respuestas anteriores, no se solicita nada ni se factura nada.
Notas
- Precios: un precio fijo por verificación para cada proveedor, consulte GET /apiv2/screening/providers; se cobra del saldo en TRX al tipo de cambio vigente en el momento del cargo.
- Tiempo de procesamiento: la mayoría de las comprobaciones finalizan en pocos segundos; una dirección con un historial extenso puede demorarse hasta tres minutos. Utilice el modo asíncrono y consulte el resultado con GET /apiv2/screening/{client_order_id}.
- Las direcciones inactivas devuelven
skippedy no se cobran. - La respuesta sin procesar del proveedor nunca se devuelve.
provider_dataes una proyección revisada; los campos pertenecientes a nuestra cuenta con el proveedor y no a la dirección verificada no se publican a nadie.
Informes
El endpoint devuelve JSON y nada más. No ofrece formato PDF ni Markdown.
Todo lo que compone un informe ya se encuentra en la respuesta: el bloque unificado y provider_data. Generarlo de su lado le proporciona el documento que realmente necesita —con su propia identidad de marca, idioma y diseño—, lo cual es especialmente oportuno si revende verificaciones, ya que un informe con nuestro nombre es un documento inadecuado para entregar a su propio cliente.
Si necesita un informe como comprobante para un tercero —un banco, un regulador, una contraparte—, tenga en cuenta que un PDF sin firmar no constituye una prueba legal, sin importar quién lo genere: puede modificarse con un editor de texto en un minuto. Un archivo verificable precisa de una firma o de una página de validación pública, lo cual constituye una funcionalidad distinta. Si este es su caso, indíquenos qué requisitos exige su contraparte.
En el panel de NETTS existen informes legibles en PDF para las mismas verificaciones, en diecisiete idiomas.
Consulte También
- GET /apiv2/screening/{client_order_id} — consultar una verificación
- GET /apiv2/screening/history — su historial de verificaciones, con paginación por cursor
- GET /apiv2/screening/providers — proveedores, precios, redes, escalas
- GET /apiv2/screening/price — precio de un proveedor
- Sanciones en un resultado AML — qué indica
sanctionsy qué indica el indicador del proveedor