Skip to content
This translation is behind the English original, updated 2026-09-15. Read the English version for the current text.

POST /apiv2/screening

Solicite una verificación AML para una dirección de blockchain. Este es el contrato de la versión 2: una única estructura de respuesta para cada proveedor y cada estado de la orden, números decimales como cadenas de texto y un formato de error único.

Reemplaza a POST /apiv2/aml, que sigue funcionando y no se retirará sin previo aviso.

URL del endpoint

POST https://netts.io/apiv2/screening

Encabezados de solicitud

HeaderRequiredDescription
Content-Typeapplication/json
X-API-KEYSu clave de API del panel de control de Netts
X-Idempotency-KeyNoSu propia clave para reintentos seguros. Consulte Idempotencia

Cuerpo de la solicitud

json
{
    "address": "YOUR_ADDRESS_HERE",
    "network": "trx",
    "provider": "elliptic",
    "wait_for_result": true
}

Parámetros

ParameterTypeRequiredDescription
addressstringDirección a verificar, de 10 a 128 caracteres
networkstringTicker de la red. Los tickers que cubre cada proveedor se enumeran en GET /apiv2/screening/providers; la tabla completa de redes con sus nombres está aquí
providerstringelliptic o bitok. No hay un valor predeterminado
wait_for_resultbooleanNotrue espera el resultado durante un máximo de 15 segundos. Valor predeterminado false
languagestringNoIdioma del informe. Solo en

Los campos desconocidos se rechazan. Un cuerpo que contenga un campo que no esté en la tabla anterior devuelve 400 con el código 4001. En la versión 1, los campos desconocidos se ignoraban silenciosamente, y un error tipográfico en wait significaba que el emisor de la llamada esperaba un resultado que nunca llegaría de forma síncrona.

provider es obligatorio y no tiene valor predeterminado. En la versión 1, omitir el proveedor significaba Elliptic, por lo que un emisor que no elegía pagaba por un proveedor que nunca había especificado.

provider es una cadena de texto libre en el esquema, no una enumeración. En la actualidad se aceptan dos valores; un tercer proveedor no debe suponer un cambio disruptivo para nadie que valide las respuestas con el esquema. La lista actual, las redes que cubre cada proveedor y la escala en la que puntúa cada uno provienen de GET /apiv2/screening/providers.

Ejemplos

cURL — esperar el resultado

bash
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 consultar periódicamente

bash
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

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

SituationCodeHeaders
Orden creada, la verificación se ejecuta en segundo plano202 AcceptedLocation: /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 cobró nada200 OK
La dirección no tiene actividad en la blockchain, no se cobró nada200 OK
Errorconsulte ErroresContent-Type: application/problem+json

Las respuestas que contienen un resultado de verificación se envían con Cache-Control: private, no-store.

Respuesta

json
{
  "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 suministra es null; una lista que no contiene nada 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 agregan nuevos campos a estos bloques sin una nueva versión. Rechazar un campo desconocido es un error de su parte, no nuestro;
  • provider_data no forma parte del contrato. Su estructura sigue al proveedor, y cambia cuando este cambia. Todo lo que garantiza el contrato reside en los bloques anteriores.

order

FieldTypeDescription
client_order_idstringIdentificador de la orden, utilizado para leer el resultado más tarde
statusstringpending, processing, completed, skipped, failed
api_versionstringContrato que creó la orden
cache_hitbooleantrue cuando se reutilizó un resultado reciente y no se cobró nada
created_atstringRFC 3339, UTC, microsegundos
started_atstring | nullMomento en el que comenzó la llamada al proveedor. null para skipped
completed_atstring | nullMomento en el que llegó el resultado
errorstringSolo para failed: motivo por el cual falló
reasonstringSolo para skipped: address_inactive

Todas las marcas de tiempo son UTC, RFC 3339, con sufijo Z y precisión de microsegundos.

billing

FieldTypeDescription
chargedbooleanSi se dedujo dinero
price_usdtstringPrecio de lista del proveedor en USDT
base_amountstringPrecio de la orden en la moneda cobrada, sin margen de subusuario
markup_amountstringMargen del subusuario. "0" para una cuenta directa
charged_amountstringLo que se dedujo efectivamente del saldo
charged_currencystringTRX
exchange_ratestring | nullTasa utilizada para la conversión
payment_statusstringpaid, pending, failed, not_charged

payment_status permanece en pending durante un breve período tras una verificación exitosa: el cargo se retiene primero y se liquida dentro de la hora. failed significa que el dinero fue reembolsado. not_charged significa que nunca se generó ningún cargo — un resultado reutilizado o una dirección omitida.

precheck

Antes de una verificación paga, 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 le cobra.

FieldTypeDescription
activity_checkedbooleanSi la verificación se ejecutó. false en redes donde no existe
activity_statusstringactive, inactive, unknown
sourcestring | nullNombre del mecanismo

unknown no detiene la verificación paga: si el servicio de actividad no está disponible, la dirección se trata como activa.

check

FieldTypeDescription
providerstringProveedor que realizó la verificación
provider_check_idstring | nullEl identificador propio del proveedor — indíquelo si disputa un resultado con ellos
checked_atstring | nullMomento en el que el proveedor generó el resultado
statusstringConsulte la tabla a continuación
provider_statusstring | nullLa redacción propia del proveedor, sin modificaciones
order.statuscheck.statusMeaning
pendingpendingOrden aceptada, aún no iniciada
processingrunningEl proveedor está trabajando en ello
completedcompletedResultado recibido
failedfailedRechazada antes o durante la llamada al proveedor
skippednot_performedLa dirección no tiene actividad; nunca se llamó al proveedor y no se cobró nada

risk

FieldTypeDescription
scorestring | nullLa puntuación propia del proveedor, como una cadena decimal
scaleobjectmin y max de la escala de ese proveedor
levelstringnone, low, medium, high, severe
level_sourcestringcomputed — derivamos el nivel a partir de la puntuación; provider — el proveedor lo indicó
provider_levelstring | nullLa palabra propia del proveedor, cuando devuelve una
policystringNombre de la política de umbrales, netts-risk-v1
by_directionobjectPuntuación dividida en source y destination, cuando el proveedor la divide

La puntuación nunca se reescala. Elliptic opera de 0 a 10 y BitOK de 0 a 1, y 7 en una escala no equivale en ningún sentido significativo a 0.7 en la otra. 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 utiliza un único vocabulario en toda la API. Cuando el proveedor indica un nivel propio, lo transmitimos directamente y lo señalamos en level_source; cuando no lo hace, derivamos el nivel a partir de la puntuación con los umbrales de netts-risk-v1 y lo indicamos en su lugar. La misma palabra aparece en la respuesta de la API, el panel de control y el informe en PDF para la 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[] lista las entidades a las que pertenece la propia dirección; primary_entity selecciona una de ellas mediante una regla fija — la entidad que el proveedor marcó como principal; en su defecto, la primera; si no hay ninguna, null. sanctioned_entities[] contiene aquellas entidades de entities[] que están 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".

text
Elliptic reports 31.574732212596924 %  ->  "share_fraction": "0.31574732212596924"
BitOK reports    0.8488                ->  "share_fraction": "0.8488"

Los proveedores difieren en las unidades: el mismo tercio de exposición llega como 31.57 desde uno y como 0.3157 desde el otro. Sería imposible interpretar un único campo que contuviera ambos sin conocer al proveedor. El número original del proveedor en sus propias unidades se conserva en provider_data.

Los números son cadenas de texto

Cada número procedente de un proveedor — puntuaciones, participaciones, volúmenes en USD y cada importe en billing — es una cadena decimal.

json
"score": "0.9634087310611608"

Analizarlo como un número JSON en JavaScript, Go o cualquier otro lenguaje con coma flotante binaria produce una aproximación, y el valor que se imprime deja de coincidir con el valor emitido por el proveedor. Analice 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 comunes.

Reutilización de un resultado reciente

Cuando verifica la misma dirección, red y proveedor nuevamente dentro de 60 segundos, se devuelve el resultado anterior y no se cobra nada.

Cada solicitud sigue creando su propia orden con su propio client_order_id; la reutilizada se marca con "cache_hit": true y su bloque billing reporta "charged": false con "payment_status": "not_charged". El identificador de la orden de la que provino el resultado no se revela — puede pertenecer a otra cuenta.

La reutilización solo ocurre dentro de una misma cuenta. Un resultado verificado por otra persona nunca se le devolverá a usted.

Idempotencia

Envíe X-Idempotency-Key con un valor propio para que el reintento sea seguro: la misma clave con el mismo cuerpo devuelve la respuesta almacenada en lugar de solicitar una segunda verificación.

SituationCodeResponse
La primera solicitud con esta clave todavía se está ejecutando4094090
La misma clave, un cuerpo de solicitud diferente4094093
La misma clave, el mismo cuerpo, ya finalizadael código almacenadola respuesta almacenada

Si no envía el encabezado, se genera una clave automáticamente a partir de la clave de 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, pero no contra una repetición un minuto después: esta última constituye una orden nueva genuina y se cobra.

El alcance de las claves es por endpoint. El mismo valor enviado a POST /apiv2/aml y a este endpoint representa dos promesas independientes sobre dos solicitudes diferentes — los cuerpos difieren, al igual que las respuestas. Reutilizar su clave mientras migra una integración de la versión 1 a la versión 2 es seguro: no le devolverá una respuesta de la versión 1 ni se considerará la misma clave utilizada con un cuerpo diferente.

Respuestas de error

Cada error generado por la aplicación utiliza RFC 9457 con Content-Type: application/problem+json:

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 se mantiene como una extensión para que las integraciones desarrolladas para la versión 1 puedan seguir comparándolo. Los campos adicionales dependen del error y deben ignorarse cuando no los reconozca.

CodeHTTPMeaning
4000400El cuerpo no es un JSON válido
4001400Un campo no superó la validación o se envió un campo desconocido
4002403El proveedor no está disponible para su cuenta
4003400Identificador de orden con formato incorrecto
4004400El proveedor no admite la red solicitada
4010401Falta la clave de API
4011401Clave de API o dirección IP no aceptada
4040404Orden no encontrada
4041404Cuenta no encontrada
4090409Una solicitud con esta clave de idempotencia aún se está ejecutando
4091409Solicitud duplicada
4093409Esta clave de idempotencia se utilizó con un cuerpo diferente
1004403Saldo insuficiente
5000500Error interno
5001500El cobro no se completó
5002500La orden no fue creada
5030503El proveedor no está disponible

Errores que no utilizan este formato

Algunos fallos ocurren en la pasarela, antes de llegar a la aplicación, y conservan la estructura propia de la pasarela. Considere cualquier respuesta cuyo Content-Type no sea application/problem+json como uno de estos casos:

SituationHTTPBody
Sin clave de API o clave no aceptada401{"detail":{"code":-1,"msg":"Invalid or missing API key"}}
Límite de tasa excedido429{"message":"API rate limit exceeded"}
Ruta desconocida o método no admitido por la ruta404 / 405{"detail":"Method Not Allowed"}

Límites de tasa

El límite se comparte con POST /apiv2/aml y las demás rutas de AML: 5 solicitudes por segundo y 150 por minuto. Migrar a este endpoint no le otorga una cuota adicional.

Notas

  • Precios: Elliptic $0.98, BitOK $0.50 por verificación, cobrados del saldo en TRX a la tasa vigente al momento del cobro.
  • Tiempo de procesamiento: la mayoría de las verificaciones finalizan en unos pocos segundos; una dirección con un historial extenso puede tardar hasta tres minutos. Utilice el modo asíncrono y lea el resultado con GET /apiv2/screening/{client_order_id}.
  • Las direcciones inactivas devuelven skipped y no se cobran.
  • La respuesta sin procesar del proveedor nunca se devuelve. provider_data es una proyección revisada; los campos que pertenecen 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 hay PDF ni Markdown.

Todo de lo que se compone un informe ya está en la respuesta: el bloque unificado y provider_data. Renderizarlo por su cuenta le proporciona el documento que realmente necesita — su marca, su idioma, su diseño — lo cual es especialmente relevante si revende verificaciones, ya que un informe con nuestro nombre no es el documento adecuado 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, independientemente de quién lo genere: puede editarse en un editor de texto en un minuto. Un archivo verificable necesita una firma o una página de verificación pública, y esa es una funcionalidad diferente. Si este es su caso, indíquenos los requisitos de su contraparte.

Existen informes en PDF legibles para humanos de las mismas verificaciones en el panel de control de Netts, en diecisiete idiomas.

Véase también