Pular para o conteúdo

Dúvidas frequentes de integração

Este guia cobre o produto KYT atual para a Demo VASP Ltda. /api/v1/kyc/* e os eventos kyc.* não estão disponíveis nesse produto. Nas rotas B2B de cases, após autenticação e acesso da conta, o gate devolve 403 PRODUCT_MODULE_DISABLED. Contratação e habilitação de KYC são separadas, sem data prometida.

Os blocos Requisição são descritores para o cliente HTTP: method, path, headers e, quando aplicável, body. Esses campos externos não são enviados no JSON da API: envie somente body, com o método e os headers indicados. Os caminhos incluem /api/v1; use a base de produção https://crypto-api.sentinexrisk.com ou a base sandbox correspondente. ${SENTINEX_API_KEY} e ${SENTINEX_WEBHOOK_SECRET} são variáveis locais, não credenciais literais. No sandbox, use chave sand e fixtures; na produção, live.

Todas as respostas abaixo são recortes JSON dos campos relevantes, não respostas completas para copiar como mocks. Os valores são sintéticos e ilustram a condição descrita, sem garantir esse resultado para toda chamada. O contrato completo está em Referência da API. Recomendações e cobertura estão detalhadas em Como as regras decidem.

HOLD também indica evidência incompleta. Sanção negativa medida não resolve cotação, agregado ou cobertura degradada. Confira fail_closed, reasons e coverage.input_assessments; retenha e reprocesse a causa. Uma sanção não medida sai com hit: null, não false.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-hold-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"recommendation": "HOLD",
"fail_closed": true,
"sanctions": {
"state": "NOT_MEASURED",
"hit": null
}
}
}

2. Por que customer_ref aparece como h:v1:… em registros de correlação?

Seção intitulada “2. Por que customer_ref aparece como h:v1:… em registros de correlação?”

Toda referência não vazia passa por HMAC versionado e isolado por tenant, mesmo sem CPF ou e-mail reconhecido. Não é criptografia reversível nem id do cadastro. Preserve seu identificador opaco no seu sistema e reenvie a referência original nas novas análises. h:v1: é uma versão possível, não formato fixo para parsing. O POST/GET de screening atual não ecoa customer_ref como campo de topo de data; não dependa desse eco. O recorte abaixo mostra o identificador correto para consulta.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-ref-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"screening_id": "00000000-0000-4000-8000-000000000001",
"client_transaction_id": "demo-operacao-001"
}
}

Faça outro POST com nova Idempotency-Key, preservando a relação com o screening anterior no seu sistema. Repetir a chave antiga devolve o snapshot antigo. Se omitir o header e repetir o corpo com client_transaction_id, a deduplicação derivada também pode devolver o anterior. O exemplo representa uma nova medição após recuperar as fontes, sem garantia de ALLOW.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-reprocessamento-002"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"screening_id": "00000000-0000-4000-8000-000000000002",
"recommendation": "REVIEW",
"fail_closed": false
}
}

Esse estado aguarda o ato da exchange. Não significa análise assíncrona pendente. Examine a recomendação e registre ação e desfecho em PATCH /client-decision. Se ainda não há fundamento humano para concluir suspeição, mantenha a pendência até apurar.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"screening_id": "00000000-0000-4000-8000-000000000001",
"client_decision": {
"status": "PENDING_CLIENT_DECISION"
}
}
}

Não. REVIEW é recomendação. A ação operacional do cliente aceita ALLOW, HOLD ou DENY, junto com SUSPICIOUS ou NOT_SUSPICIOUS e justificativa. O exemplo pressupõe revisão humana que fundamentou a liberação. O registro não executa a operação financeira.

Requisição:

{
"method": "PATCH",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001/client-decision",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json"
},
"body": {
"client_decision": {
"operational_action": "ALLOW",
"suspicion_outcome": "NOT_SUSPICIOUS",
"rationale": "Contraparte e origem examinadas pela mesa de compliance."
}
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"screening_id": "00000000-0000-4000-8000-000000000001",
"client_decision": {
"status": "RECORDED",
"authority": "CLIENT_EXCHANGE",
"operational_action": "ALLOW",
"suspicion_outcome": "NOT_SUSPICIOUS"
}
}
}

Não nessa rota: é imutável. Após timeout ou 409, consulte o screening e reconcilie a decisão antes de agir. Nova análise não reescreve a trilha anterior.

Requisição:

{
"method": "PATCH",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001/client-decision",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json"
},
"body": {
"client_decision": {
"operational_action": "DENY",
"suspicion_outcome": "SUSPICIOUS",
"rationale": "Análise humana concluiu suspeição."
}
}
}

Resposta HTTP 409, recorte:

{
"success": false,
"error": {
"code": "KYT_CLIENT_DECISION_ALREADY_RECORDED",
"http_status": 409,
"message": "Este screening já possui decisão do cliente.",
"action": "Consulte o screening; o registro é imutável.",
"retriable": false
}
}

7. A mesma chave cria outra cobrança ou outro evento?

Seção intitulada “7. A mesma chave cria outra cobrança ou outro evento?”

Mesmo tenant, mesma chave e mesmos bytes produzem replay HTTP 200 com o snapshot original, sem nova análise, novo uso ou emissão duplicada pelo caminho de replay. GET também consulta evidência já gravada, não reexecuta o motor.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-replay-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"idempotent_replay": true,
"data": {
"screening_id": "00000000-0000-4000-8000-000000000001",
"recommendation": "REVIEW"
}
}

A chave já foi usada com outro corpo. Ordem de campos, espaços e representação numérica alteram os bytes. Guarde e reenvie os bytes originais para a mesma intenção. Use outra chave apenas para uma intenção nova, não para contornar um conflito que ainda precisa reconciliar.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-replay-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 2
}
}

Resposta HTTP 409, recorte:

{
"success": false,
"error": {
"code": "KYT_IDEMPOTENCY_CONFLICT",
"http_status": 409,
"message": "A Idempotency-Key foi reutilizada com outro corpo.",
"action": "Use uma nova chave para outra intenção.",
"retriable": false
}
}

No screening com client_transaction_id, o servidor deriva chave por corpo e janelas de 10 minutos, consultando também a anterior, alcance de 10 a 20 minutos. Sem ambos, pode criar nova análise. Prefira chave explícita. O conflito concorrente abaixo pode ocorrer na disputa pela mesma intenção; espere os segundos indicados.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5
}
}

Resposta HTTP 409, recorte:

{
"success": false,
"error": {
"code": "KYT_IDEMPOTENCY_IN_PROGRESS",
"http_status": 409,
"message": "Um screening idêntico está em processamento.",
"action": "Repita com a mesma chave.",
"retriable": true,
"retry_after_seconds": 2
}
}

Não. O prefix gate recusa snxc_test_ e snxc_sand_ em produção com 403 antes da verificação da chave. Use chave live aprovada e emitida no painel. Sandbox aceita seu prefixo sand. Prefixo desconhecido ou chave inválida pode chegar ao 401 de autenticação.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/alerts",
"headers": {
"X-API-Key": "snxc_test_<exemplo_sem_segredo>"
}
}

Resposta HTTP 403, recorte:

{
"success": false,
"error": {
"code": "api_key_environment_not_allowed",
"message": "API key environment is not allowed for this route"
}
}

POST de screening, client-decision e tx-hash exigem vasp:transactions:screen; GET do screening e alertas exigem vasp:read. Cadastros e webhooks têm escopos próprios. O tenant vem da chave, sem header de tenant. Falta de escopo retorna 403.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 403, recorte:

{
"success": false,
"error": {
"code": "insufficient_scope",
"message": "API key missing required scope: vasp:read"
}
}

12. Por que recebi 429 abaixo de 2.000 chamadas por minuto?

Seção intitulada “12. Por que recebi 429 abaixo de 2.000 chamadas por minuto?”

O limite do tenant soma usuários e chaves, mas a chave possui limite próprio, padrão 60/min. O laudo tem 120/h por IP; buscas e lotes também têm limites específicos. Respeite Retry-After, quando vier. Não presuma que o plano define o limite gravado na chave.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/alerts?limit=1",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 429, recorte:

{
"success": false,
"error": {
"code": "api_key_rate_limit_exceeded",
"message": "API key rate limit exceeded"
}
}

Não. Os limitadores falham fechados com 503. Esse erro não é recomendação HOLD gravada. Espere e repita com a mesma chave de idempotência nas operações que a suportam.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-contador-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5
}
}

Resposta HTTP 503, recorte:

{
"success": false,
"error": {
"code": "rate_limit_unavailable",
"message": "Rate limit service is unavailable"
}
}

Com chave válida, conta liberada e limites atendidos, caminho ou método inexistente no segmento /api/v1/vasp recebe esse código. Confira base, prefixo e método. Não troque por Bearer de usuário para tentar acessar uma operação inexistente.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/rota-inexistente",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 404, recorte:

{
"success": false,
"error": {
"code": "route_not_found",
"message": "Nenhuma rota desta API atende este método e caminho."
}
}

Gere localmente de 32 a 128 bytes aleatórios e envie em secret; a resposta nunca ecoa o valor. A variável no exemplo é substituída em memória, não é secret para uso literal. Use HTTPS público sem credenciais, query ou fragmento e escopo vasp:webhooks:manage. O contrato não oferece rotação: crie nova subscription e remova a anterior após validar.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/webhooks",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json"
},
"body": {
"target_url": "https://hooks.demovasp.com.br/sentinex",
"events": [
"kyt.screening.completed"
],
"secret": "${SENTINEX_WEBHOOK_SECRET}"
}
}

Resposta HTTP 201, recorte:

{
"success": true,
"id": "00000000-0000-4000-8000-000000000002",
"target_url": "https://hooks.demovasp.com.br/sentinex",
"events": [
"kyt.screening.completed"
]
}

16. Como valido HMAC e impeço replay no receptor?

Seção intitulada “16. Como valido HMAC e impeço replay no receptor?”

Assine a concatenação literal timestamp + ponto + corpo cru com HMAC SHA-256, compare o hex em tempo constante e confira a janela de timestamp no seu receptor. Leia X-Sentinex-Signature e X-Sentinex-Timestamp antes de interpretar JSON. Deduplique event_id mais delivery_id; uma retentativa muda attempt e a assinatura. O teste abaixo enfileira entrega, não prova recepção. O verificador completo está no guia de Webhooks.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/webhooks/00000000-0000-4000-8000-000000000002/test",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 202, recorte:

{
"success": true,
"subscription_id": "00000000-0000-4000-8000-000000000002",
"event_id": "00000000-0000-4000-8000-000000000001",
"status": "pending"
}

Na subscription /vasp/webhooks são até 10 tentativas, timeout de 10 segundos por entrega: intervalos 2, 4, 8, 16, 32 e depois 60 minutos. Dez falhas consecutivas pausam a subscription; acompanhe active e consecutive_failures. A API key não reativa: corrija o receptor e crie outra subscription. Replay governado de entrega é operação do painel. O exemplo consulta as subscriptions, não força retry. A lista real vem em data como array; o schema genérico publicado ainda a tipa como objeto, divergência registrada para correção. O recorte mostra somente o campo comum.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/webhooks",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 200, recorte:

{
"success": true
}

18. Assinei alert.escalated e customer.updated. Por que não chegam?

Seção intitulada “18. Assinei alert.escalated e customer.updated. Por que não chegam?”

São aceitos na assinatura, mas ainda não emitidos; também customer.deleted e kyc.completed. Eventos kyc.* não estão disponíveis no produto KYT. Sucesso no cadastro não comprova emissão. Para alerta novo use alert.created e reconcilie em GET /vasp/alerts. Não há promessa de data para novos emissores.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/webhooks",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json"
},
"body": {
"target_url": "https://hooks.demovasp.com.br/sentinex",
"events": [
"alert.escalated"
],
"secret": "${SENTINEX_WEBHOOK_SECRET}"
}
}

Resposta HTTP 201, recorte:

{
"success": true,
"id": "00000000-0000-4000-8000-000000000002",
"target_url": "https://hooks.demovasp.com.br/sentinex",
"events": [
"alert.escalated"
]
}

19. Posso usar /kyc/cases com minha integração KYT?

Seção intitulada “19. Posso usar /kyc/cases com minha integração KYT?”

Não. Essa superfície não integra o contrato do cliente KYT. Nas rotas de cases montadas com API key, o gate do produto recusa KYC com 403 PRODUCT_MODULE_DISABLED após os gates anteriores. Não é 404 por case inexistente. Um produto que habilite KYC, módulo contratado, escopos kyc:read/kyc:write, políticas e workflows publicados são requisitos separados. Não há data prometida. O exemplo é uma recusa fora do contrato KYT, incluída para diagnóstico.

Requisição:

{
"method": "GET",
"path": "/api/v1/kyc/cases/00000000-0000-4000-8000-000000000001",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 403, recorte:

{
"success": false,
"error": "Módulo não disponível neste produto.",
"code": "PRODUCT_MODULE_DISABLED",
"details": {
"module": "mod_crypto_kyc"
}
}

Não. É declarado para conferência e volta em declared_fiat_value_brl. O servidor mede amount_brl a partir da quantidade e da cotação; se não consegue, retorna null e HOLD. Alterar apenas o valor declarado não substitui medição.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-brl-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5,
"fiat_value_brl": 7500.5
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"declared_fiat_value_brl": 7500.5,
"amount_brl": null,
"recommendation": "HOLD",
"fail_closed": true
}
}

Essa omissão isolada não. Ela produz UNKNOWN e NOT_MEASURED por falta de declaração. Não confunda isso com serviço de transmissão contratado ou com dispensa regulatória. Outros insumos continuam podendo reter a análise.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-travel-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"obligations": {
"travel_rule": "UNKNOWN"
},
"coverage": {
"input_assessments": {
"travel_rule": {
"state": "NOT_MEASURED",
"reason": "informação não declarada"
}
}
}
}
}

Sem customer_ref, ou com política monetária desativada, não há avaliação do limiar agregado e a omissão não impõe HOLD por essa regra. Com referência e limiar ativo, falha da leitura vira NOT_MEASURED e retenção. Não converta nenhum desses estados em total zero.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-agregado-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"coverage": {
"input_assessments": {
"aggregate_7d": {
"state": "NOT_EVALUATED",
"reason": "sem identificação do titular"
}
}
}
}
}

23. O provedor respondeu ok. Todas as capacidades foram medidas?

Seção intitulada “23. O provedor respondeu ok. Todas as capacidades foram medidas?”

Não. Leia sanctions, labels, exposures, graph e typologies separadamente. NOT_MEASURED não é resultado negativo. Quando a dimensão não é oferecida por desenho, not_covered explica a ausência; quando falhou um insumo oferecido, a cobertura degrada e a análise é retida.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"capabilities": {
"sanctions": "MEASURED",
"labels": "NOT_MEASURED",
"exposures": "NOT_MEASURED",
"graph": "NOT_MEASURED",
"typologies": "NOT_MEASURED"
},
"direct_exposure": null,
"indirect_exposure": null
}
}

Não. label_evidence descreve um fato do emissor com efeito LABEL_ONLY; não fabrica sanção, exposição ou score. Para sanção, confira sanctions.state, hit e evidência verificada. O recorte mostra uma consulta negativa de sanção, não uma garantia sobre as outras dimensões.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"sanctions": {
"state": "MEASURED",
"hit": false
}
}
}

rule_hits lista acionamentos, não o universo avaliado. Leia coverage.evaluable_rules, degraded_rules, disabled_rules e causas. O catálogo GET /api/v1/rules fica na área logada e informa os insumos e pipelines de cada regra, sem abrir essa rota à chave B2B. Veja Como as regras decidem para o manifesto por regra.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"rule_hits": [],
"coverage": {
"state": "ACTIVE_DEGRADED",
"degraded_rules": [
{
"rule_id": "R-CRYPTO-37",
"source": "onchain_intelligence",
"cause": "SOURCE_UNAVAILABLE"
}
]
}
}
}

Não. Só observa quando tem base real para avaliar; suas observações ficam separadas dos hits decisórios. O shadow do tenant é configuração auditada; shadow global é autoridade de plataforma. Uma lista vazia de observações não prova que a regra foi avaliada.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"shadow_observations": []
}
}

Não. RESOLVED só confirma titular do tenant. Cruzamento depende do adicional contratado, políticas e fatos disponíveis; com cruzamento desligado nenhuma fonte KYC é lida. UUID desconhecido ou de outro tenant produz NOT_FOUND sem alterar score ou recomendação por esse fato. UUID inválido retorna 422 antes de analisar. KYC próprio não está disponível no produto KYT atual.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-titular-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5,
"customer_id": "00000000-0000-4000-8000-000000000002"
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"customer_id": "00000000-0000-4000-8000-000000000002",
"holder_resolution": "NOT_FOUND"
}
}

28. Posso analisar antes de transmitir e anexar tx_hash depois?

Seção intitulada “28. Posso analisar antes de transmitir e anexar tx_hash depois?”

Sim. Omita tx_hash no POST e use PATCH /tx-hash após transmitir. O anexo é imutável, repetir o mesmo hash é idempotente e outro hash conflita. Formato válido não prova existência on-chain; a verificação continua NOT_MEASURED. O exemplo usa hash sintético sem transação real.

Requisição:

{
"method": "PATCH",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001/tx-hash",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json"
},
"body": {
"tx_hash": "0x1111111111111111111111111111111111111111111111111111111111111111"
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"on_chain_verification": "NOT_MEASURED",
"origin": "TX_HASH_PATCH"
}
}

O alerta criado pelo screening sinalizado recebe sla_deadline de criação mais 1 hora para CRITICAL e mais 4 horas para HIGH. A prioridade considera o risco anterior à política. Esses prazos de fila não são promessa de resolução nem SLA do suporte. Leia o prazo efetivo do alerta; outras origens podem ter políticas próprias.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/alerts?limit=1&offset=0",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"pagination": {
"total": 1,
"limit": 1,
"offset": 0
},
"data": [
{
"id": "00000000-0000-4000-8000-000000000001",
"severity": "HIGH",
"sla_deadline": "2026-11-01T16:00:00Z",
"sla_breached": false
}
]
}

30. Por que recebi 404 para um screening existente em outra conta?

Seção intitulada “30. Por que recebi 404 para um screening existente em outra conta?”

A leitura é isolada por tenant. Um id de outro tenant recebe o mesmo KYT_SCREENING_NOT_FOUND de um id inexistente. Não tente enviar tenant_id no corpo ou header. Confira a chave usada na criação e preserve o screening_id.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 404, recorte:

{
"success": false,
"error": {
"code": "KYT_SCREENING_NOT_FOUND",
"http_status": 404,
"message": "O screening não foi encontrado neste tenant.",
"action": "Confirme o identificador.",
"retriable": false
}
}

31. Atingir o limiar COAF não envia comunicação: o que acontece?

Seção intitulada “31. Atingir o limiar COAF não envia comunicação: o que acontece?”

Não. A política de suspeição é interna, opt-in, padrão desligado e limiares 0, sem piso legal de comunicação de operação suspeita. MONITOR em coaf_sar é legado; coaf_objective é prévia, não protocolo aceito. O estado objetivo deve ser examinado separadamente. A base legal e as fontes oficiais estão em Como as regras decidem.

Requisição:

{
"method": "GET",
"path": "/api/v1/vasp/screenings/00000000-0000-4000-8000-000000000001",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}"
}
}

Resposta HTTP 200, recorte:

{
"success": true,
"data": {
"obligations": {
"coaf_sar": "MONITOR",
"coaf_objective": {
"state": "INDETERMINADA",
"final": false,
"gaps": [
"PREVIEW_ONLY",
"CONFIRMED_EVENT_MISSING"
]
}
}
}
}

Não. Se a identidade pseudonimizada não puder ser obtida, o handler devolve 503 KYT_IDENTITY_UNAVAILABLE com data.recommendation HOLD e fail_closed true, sem criar análise ou cobrar. É diferente do HOLD HTTP 200 já registrado. Respeite o status e reconcilie usando a mesma chave de idempotência; não gere nova chave em toda falha de rede.

Requisição:

{
"method": "POST",
"path": "/api/v1/vasp/screenings",
"headers": {
"X-API-Key": "${SENTINEX_API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "demo-identidade-001"
},
"body": {
"client_transaction_id": "demo-operacao-001",
"customer_ref": "demo-cliente-001",
"asset": "ETH",
"chain": "ethereum",
"counterparty_address": "0x7eae68ba864d7e60463ca6842c53f1b20ecfb1a2",
"direction": "WITHDRAWAL",
"amount": 1.5
}
}

Resposta HTTP 503, recorte:

{
"success": false,
"error": {
"code": "KYT_IDENTITY_UNAVAILABLE",
"http_status": 503,
"message": "Identidade temporariamente indisponível.",
"action": "Mantenha a operação em HOLD e repita após a recuperação do serviço de chaves.",
"retriable": true,
"retry_after_seconds": 30
},
"data": {
"recommendation": "HOLD",
"fail_closed": true
}
}

Para assinatura, retries e eventos efetivamente emitidos, veja Webhooks. Para bytes de replay e deduplicação derivada, veja Idempotência. Termos em Glossário.