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.
1. Por que recebi HOLD sem sanção?
Seção intitulada “1. Por que recebi HOLD sem sanção?”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" }}3. Como reprocessar depois que a fonte voltou?
Seção intitulada “3. Como reprocessar depois que a fonte voltou?”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 }}4. O que faço com PENDING_CLIENT_DECISION?
Seção intitulada “4. O que faço com PENDING_CLIENT_DECISION?”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" } }}5. Posso enviar REVIEW como minha decisão?
Seção intitulada “5. Posso enviar REVIEW como minha decisão?”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" } }}6. Posso alterar uma decisão já registrada?
Seção intitulada “6. Posso alterar uma decisão já registrada?”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" }}8. O que significa KYT_IDEMPOTENCY_CONFLICT?
Seção intitulada “8. O que significa KYT_IDEMPOTENCY_CONFLICT?”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 }}9. E se eu não enviar Idempotency-Key?
Seção intitulada “9. E se eu não enviar Idempotency-Key?”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 }}10. Uma chave test funciona na produção?
Seção intitulada “10. Uma chave test funciona na produção?”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" }}11. Quais escopos uso para analisar e consultar?
Seção intitulada “11. Quais escopos uso para analisar e consultar?”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" }}13. Contador indisponível libera a chamada?
Seção intitulada “13. Contador indisponível libera a chamada?”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" }}14. O que significa 404 route_not_found?
Seção intitulada “14. O que significa 404 route_not_found?”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." }}15. Como cadastro o webhook sem expor o secret?
Seção intitulada “15. Como cadastro o webhook sem expor o secret?”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"}17. Quantas tentativas de webhook existem?
Seção intitulada “17. Quantas tentativas de webhook existem?”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" }}20. fiat_value_brl controla os limiares?
Seção intitulada “20. fiat_value_brl controla os limiares?”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 }}21. Deixar travel_rule ausente causa HOLD?
Seção intitulada “21. Deixar travel_rule ausente causa HOLD?”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" } } } }}22. Por que aggregate_7d veio NOT_EVALUATED?
Seção intitulada “22. Por que aggregate_7d veio NOT_EVALUATED?”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 }}24. Uma label de bloqueio de emissor é sanção?
Seção intitulada “24. Uma label de bloqueio de emissor é sanção?”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 } }}25. Onde descubro quais regras estavam aptas?
Seção intitulada “25. Onde descubro quais regras estavam aptas?”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" } ] } }}26. Uma regra shadow muda minha recomendação?
Seção intitulada “26. Uma regra shadow muda minha recomendação?”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": [] }}27. customer_id resolvido garante KYC completo?
Seção intitulada “27. customer_id resolvido garante KYC completo?”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" }}29. Qual é o prazo de um alerta?
Seção intitulada “29. Qual é o prazo de um alerta?”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" ] } } }}32. Todo HOLD vem com HTTP 200?
Seção intitulada “32. Todo HOLD vem com HTTP 200?”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.