Versionamento e changelog
O que é versionado
Seção intitulada “O que é versionado”O contrato do cliente KYT é o arquivo openapi.yaml publicado neste site, e a versão dele é o campo info.version. Ele descreve as operações que a API de produção serve a uma integração autenticada por chave de API, todas relativas a https://crypto-api.sentinexrisk.com/api/v1.
A versão do contrato do cliente é própria. A versão do serviço que GET /api/v1/version devolve identifica o binário em execução, e a especificação interna da plataforma e os SDKs têm numeração deles: nenhuma das duas indica mudança deste contrato.
Política
Seção intitulada “Política”| Regra | O que significa para você |
|---|---|
| O contrato v1 do primeiro cliente é a linha 8.x | Toda versão 8.x.y roda sob /api/v1. A partir do congelamento, toda versão nova é compatível com a anterior |
| A linha congela no primeiro integrador | info.x-snx-congelamento diz a fase. Com pre-integracao, ainda não há integrador em produção, e uma operação que não serve ao produto KYT pode sair do contrato, sempre nomeada em código na entrada do changelog e marcada como mudança incompatível. Só remoção de operação é permitida assim; qualquer outra mudança incompatível segue proibida em qualquer fase. Quando o primeiro integrador recebe a chave, o valor passa a congelado desde dd/mm/aaaa, e a fase não volta |
Mudança incompatível só com /api/v2 |
Depois do congelamento, remover operação ou campo, tornar obrigatório o que era opcional, mudar tipo ou restringir valores aceitos não acontece sob /api/v1. Uma mudança assim exige um prefixo novo, /api/v2, com a major seguinte do contrato. Hoje não existe /api/v2 |
| Mudança aditiva sobe o minor | Operação nova, campo novo na resposta ou parâmetro opcional novo: 8.0.0 vira 8.1.0 |
| Correção sobe o patch | Texto de descrição, exemplo ou erro de digitação no contrato: 8.0.0 vira 8.0.1 |
| Toda mudança do contrato tem entrada neste changelog | A entrada traz a versão, a data e o que mudou |
A versão só sobe quando o conteúdo deste contrato muda: mudança na plataforma que não altera o contrato do cliente não gera versão nem entrada aqui. Para ler versões futuras sem quebrar, trate campo desconhecido na resposta e valor desconhecido de enum como possíveis, sem falhar.
Como a política é garantida
Seção intitulada “Como a política é garantida”Uma verificação automática no processo de publicação do contrato reprova:
- mudança no conteúdo do contrato do cliente sem aumento de
info.version, ou versão que desce; - versão do contrato sem entrada neste changelog;
- mudança de major sem mudança do prefixo
/api/v1; - mudança incompatível sob o mesmo prefixo, mesmo quando a versão sobe só o minor ou o patch, depois do congelamento, inclusive a potencialmente incompatível, como remover propriedade opcional da resposta ou restringir tamanho e formato aceitos na requisição;
- antes do congelamento, operação removida que não esteja nomeada em código (
MÉTODO /caminho) na entrada do changelog; - contrato sem
info.x-snx-congelamento, com data de congelamento no futuro, ou que volte de congelado parapre-integracao.
O contrato publicado neste site é gerado a partir da mesma fonte que a API usa, e as páginas da referência da API são geradas desse arquivo. Uma página que diverge do contrato reprova a publicação.
Changelog
Seção intitulada “Changelog”8.5.1 (09/11/2026)
Seção intitulada “8.5.1 (09/11/2026)”Correção de texto voltado ao integrador. Nas descrições do contrato, a chave de API identifica a empresa e carrega os escopos; nenhum header extra de empresa é necessário; a chave é criada no painel por um administrador da empresa. Não há mudança de operação, campo de payload ou comportamento servido.
8.5.0 (24/10/2026)
Seção intitulada “8.5.0 (24/10/2026)”Mudança aditiva, sem operação nova e sem campo removido. POST /vasp/screenings e GET /vasp/screenings/{id} ganham o campo opcional not_covered, no topo da resposta, com as dimensões que esta versão não analisa por desenho: exposição on-chain (exposures, graph e typologies, causa CAPABILITY_NOT_OFFERED) e blocklist de rede sem base de golpes carregada (causa NETWORK_NOT_COVERED; a base atual cobre ETH e as redes EVM que a compartilham: BASE, ARB, BSC, MATIC, AVAX, OP e FTM); se a rede tiver endereços gravados por importação anterior, a consulta é feita e o resultado é medido. Cada item traz rule_id, source e cause. ALLOW com entradas em not_covered significa que essas dimensões não foram analisadas, e não que o resultado delas foi negativo. Falha real do provedor, timeout ou erro de consulta continua retendo a triagem em HOLD e não entra neste campo. Triagens gravadas antes desta versão não trazem o campo; trate a ausência como lista vazia.
8.4.1 (15/10/2026)
Seção intitulada “8.4.1 (15/10/2026)”Correção de documentação do sandbox. A resposta 429 das chamadas VASP autenticadas passa a declarar os limites já aplicados pelo simulador, 60 requisições por minuto por key, 300 por minuto por tenant e 10.000 por dia UTC por tenant, além dos headers Retry-After, X-RateLimit-Limit e X-RateLimit-Remaining. Não há mudança de operação, campo de payload ou comportamento servido.
8.4.0 (10/10/2026)
Seção intitulada “8.4.0 (10/10/2026)”Contrato em pré-integração (info.x-snx-congelamento: pre-integracao). Duas operações entram no contrato; nenhuma sai. As demais mudanças são aditivas, esclarecem recusas que já existiam ou ajustam o formato de dados não medidos, como descrito abaixo.
POST /vasp/customers/batch: matrícula de clientes finais em lote, de 1 a 1.000 por chamada, comIdempotency-Keyobrigatória e resposta207com o resultado de cada item. Os limites próprios do lote, por chave e por tenant, respondem 429 comRetry-After: 3600e o corpoErroLimiteDoLote; a recusa de acesso (403) tem as mesmas formas das demais operações.PATCH /vasp/screenings/{id}/tx-hash: depois de pré-checar um saque e transmitir a transação, o cliente anexa o hash ao mesmo screening. O registro é imutável e idempotente: repetir o mesmo hash devolve 200 comidempotent_replay, outro hash devolve 409KYT_TX_HASH_ALREADY_ATTACHEDe hash fora do formato da rede devolve 400KYT_TX_HASH_INVALID. Não reavalia o screening, não muda a recomendação nem a decisão do cliente e não gera cobrança. A existência da transação na rede não é medida (on_chain_verificationNOT_MEASURED).GET /vasp/screenings/{id}passa a trazerdata.transaction(hash, instante e origem) depois de um anexo peloPATCH. O campo é opcional e não aparece enquanto não houver anexo.POST /vasp/screeningseGET /vasp/screenings/{id}: a resposta ganha o campo opcionallabel_evidence, com as etiquetas de bloqueio de emissor de stablecoin (USDT e USDC) lidas de eventos públicos do contrato do emissor. O campo só aparece quando há evento coletado para o endereço consultado, e a ausência de evento não prova que o endereço esteja livre. O efeito é sempreLABEL_ONLY: bloqueio de emissor é fato sobre o endereço, não é sanção e não altera o score.capabilities.labelspassa a valerMEASUREDtambém quando há essa etiqueta.POST /vasp/screenings:operation_atmais de 5 minutos adiante do relógio do servidor responde 400KYT_OPERATION_AT_IN_FUTURE, antes de qualquer análise, persistência ou cobrança. Até 5 minutos é aceito como folga de relógio, e a ausência do campo segue como antes. A tolerância é parâmetro operacional, não prazo de norma.POST /vasp/screeningseGET /vasp/screenings/{id}: dado não medido deixa de aparecer como zero ou como resultado negativo.amount_brlsainullquando a quantidade ou a cotação não foi medida (antes saía0), esanctions.hitsainullcomsanctions.stateNOT_MEASUREDquando a sanção não foi medida (antes saíafalse);nullnunca vale como limpo. É mudança de formato da resposta, feita antes do primeiro integrador (a linha segue empre-integracao), e quem integrar já deve tratarnullnesses dois campos.POST /vasp/screeningseGET /vasp/screenings/{id}:obligations.travel_rulepassa a declarar os valoresUNKNOWN,REQUIREDeNOT_REQUIRED. O servidor já emitiaREQUIREDeNOT_REQUIRED;UNKNOWNé novo e sai quando a Travel Rule não é informada na requisição. Trate qualquer valor novo nesse campo sem falhar.
8.3.1 (09/10/2026)
Seção intitulada “8.3.1 (09/10/2026)”Correção da base canônica de produção do contrato: as chamadas da integração KYT devem usar https://crypto-api.sentinexrisk.com/api/v1. A base anterior, https://api.crypto.sentinexrisk.com/api/v1, não é mais a referência de produção. O sandbox permanece em https://sandbox.api.crypto.sentinexrisk.com/api/v1.
8.3.0 (02/10/2026)
Seção intitulada “8.3.0 (02/10/2026)”Contrato em pré-integração (info.x-snx-congelamento: pre-integracao). Nenhuma operação entra nem sai do contrato. Esta versão traz o desfecho HOLD da análise que conclui sem uma evidência necessária, mudanças aditivas no laudo KYT, o formato das chaves emitidas a partir da 2.16.0 e o sandbox do desenvolvedor.
POST /vasp/screenings: quando uma evidência necessária fica indisponível ou incompleta (contraparte não triável, provedor indisponível, timeout ou resposta incompleta), a análise conclui com HTTP 200,recommendationHOLD,fail_closedverdadeiro e o motivo emreasons, com a orientação de reprocessar com a mesmaIdempotency-Key. Antes, esse desfecho respondia 503KYT_DEPENDENCY_UNAVAILABLE.HOLDé retenção temporária, não bloqueio e não confirmação de risco. Ele nunca viraALLOW, nem pela política do tenant.DENYcontinua restrito a sanção ou regra de bloqueio configurada pelo tenant e prevalece sobreHOLD.- A recomendação é da Sentinex; a decisão operacional e o desfecho de suspeição continuam sendo do cliente, registrados em
client_decision. - O 503 permanece para ausência de resultado do motor, política do tenant ilegível e falha de persistência, auditoria, medição ou infraestrutura, quando nada é registrado nem cobrado.
GET /vasp/screenings/{id}, o replay idempotente, o webhook e a decisão do cliente devolvemHOLDpara a mesma análise.
Laudo KYT (POST /vasp/kyt-report, formatos pdf, html e json):
report.idpassa a ser o identificador único da emissão, um ULID cujo instante é o da emissão. É o mesmo valor do nome do arquivo e da trilha de auditoria. Até a 2.15.x ele repetia ocase_id, e dois laudos da mesma carteira saíam com o mesmoreport.id.case.case_idfica separado e estável. Passa a ter a formaKYT-WALLET-<REDE>-<hash do endereço canônico>, com a rede pelo nome canônico em maiúsculas (ETHEREUM, e não o apelido digitado) e o hash sobre o endereço canônico. Grafias do mesmo endereço (checksum ou minúsculo) e da mesma rede dão o mesmocase_id.- Compatibilidade do histórico: laudos emitidos antes da 2.16.0 trazem o
case_idna forma antiga, calculada sobre a rede e o endereço como foram digitados, ereport.idigual a essecase_id. A mesma carteira pode aparecer em dois grupos, um antigo e um novo, até o histórico anterior expirar. Não una os dois grupos pelo texto docase_id. - O par endereço e rede é validado antes de qualquer consulta externa. Par inválido (rede desconhecida, checksum inválido ou forma de outra rede) responde
400KYT_WALLET_INVALID, com o campo novoerror.reasonigual aaddress_chain_mismatch, e nenhuma chamada externa é feita. - Valores em reais (
volume_brl,direct_brl,indirect_brl,total_brlevalue_brl) só existem com cotação completa. Os campos novosscope.brl_status(medidoounao_cotado) escope.brl_quote(moeda de origem, taxa em texto decimal, fonte e instante da cotação) dizem o estado. Emnao_cotado, nenhum campo em reais aparece no JSON, e o documento imprimeNÃO COTADO, nuncaR$ 0,00. Trate a ausência do campo como “não cotado”, e não como zero. monitoring(status,sourceeobserved_at) só aparece quando uma fonte comprova o estado de monitoramento da carteira nesta emissão. Sem ele, o documento imprimeNÃO COMPROVADO NESTA EMISSÃOem vez de afirmar monitoramento contínuo.attribution[].vasppassa a sertrue,falseounull. Contraparte observada on-chain sem atribuição de entidade sainull(não determinado), e não maisfalse.- Na resposta do download,
Content-Dispositiontraz o nomekyt-{perfil}-{emitido-em-UTC}-{report-id}.{formato}(attachmentno PDF,inlineno HTML e no JSON) eX-Report-Formattrazhtmloujson(ausente no PDF).X-Report-Audit-Trailindica se a emissão entrou no histórico imutável. O CORS expõeContent-DispositioneX-Report-Formatao navegador.
Chaves de API:
- Chaves emitidas a partir da 2.16.0 têm o formato
snxc_<ambiente>_<identificador>_<segredo>, com identificador de 32 caracteres e segredo de 64 hexadecimais, 107 caracteres no total. Trate a chave como texto opaco. Chaves anteriores,snxc_<ambiente>_<hex>, continuam válidas até a expiração ou a revogação. - Se a plataforma não consegue verificar a chave, a resposta é
503api_key_verification_unavailable, e a requisição pode ser repetida com espera. A chave nunca é tratada como válida sem verificação. - O cadastro e o provisionamento de tenant deixam de devolver chave de API (
sandbox_api_keyeapi_key_temporarynão são mais emitidos). A chavesnxc_sand_só existe no ambiente de teste e é emitida pela governança de chaves do painel, com MFA confirmada eIdempotency-Key.
Sandbox do desenvolvedor, em https://sandbox.api.crypto.sentinexrisk.com/api/v1:
- O sandbox é um ambiente separado da produção e aceita somente chave com prefixo
snxc_sand_, com validade de 30 dias. Credencial inexistente responde401; credencial de outro ambiente, como umasnxc_live_, responde403api_key_environment_not_allowed, por ambiente incompatível, sem consultar o banco. A chave do sandbox também não funciona em produção. - O simulador responde só com as oito fixtures do catálogo
sandbox-fixtures-v1e não faz chamada externa.fx-kyt-low-v1devolveALLOW;fx-kyt-review-v1,REVIEW;fx-kyt-deny-sanctions-v1,DENYpor um match sintético de sanção, a única base deDENYdo catálogo;fx-provider-error-v1efx-provider-timeout-v1,HOLDcomfail_closedverdadeiro e orientação de reprocessar. As três restantes exercitam o fluxo:fx-replay-v1(repetição da mesmaIdempotency-Key, mesmo resultado e nenhum efeito duplicado),fx-webhook-retry-v1(duas falhas de entrega e sucesso na terceira tentativa) efx-concurrent-idempotency-v1(duas requisições concorrentes, um efeito confirmado). - O identificador público de cada fixture é derivado: os 20 primeiros bytes de SHA-256 sobre
sentinex:sandbox-fixture:v1:seguido dofixture_id, em hexadecimal minúsculo com prefixo0x, na redeethereum. O catálogo, com os identificadores, os cenários e o resultado esperado de cada um, é publicado no portal do desenvolvedor (GET /sandbox/fixtures, com sessão). Os dois endereços reservados anteriores continuam respondendo o mesmo resultado, por compatibilidade, e não fazem parte do catálogo novo. - Endereço que não é fixture responde
422SANDBOX_FIXTURE_NOT_SUPPORTEDemPOST /vasp/screenings, sem consulta de DNS nem de provider. O corpo desse422usa o mesmo envelope de erro da rota (error.code,error.http_status,error.message,error.action,error.retriable), comactionapontando para/api/v1/sandbox/fixturese o catálogosandbox-fixtures-v1. Só o sandbox emite esse código. - Os limites do simulador são 60 requisições por minuto por chave, 300 por minuto por tenant e 10.000 por dia por tenant. Acima deles a resposta é
429. - Não há cobrança nem consulta livre à mainnet. O e-mail real usa credencial e subdomínio exclusivos do sandbox, limita-se a usuários do tenant e aos tipos autorizados. Os demais tipos ficam na caixa interna do tenant.
8.2.0 (29/09/2026)
Seção intitulada “8.2.0 (29/09/2026)”Contrato em pré-integração (info.x-snx-congelamento: pre-integracao). Nenhuma operação, campo ou enum muda; muda, de forma opcional, quando o misturador sai DENY.
- O tenant pode escolher, no painel, bloquear automaticamente a proibição legal do misturador (Res. BCB nº 520/2025, art. 90, III, e parágrafo único). Com a escolha ligada, a contraparte misturador sai
recommendationDENY, ereasonstraz o motivo “política do cliente: proibição legal misturador”. O padrão é desligado: sem a escolha, o misturador continua saindoREVIEWcom o rótulo da proibição, como na 8.1.1. - Sanção continua saindo
DENYem qualquer configuração, e a escolha do tenant nunca a desliga.
8.1.1 (28/09/2026)
Seção intitulada “8.1.1 (28/09/2026)”Contrato em pré-integração (info.x-snx-congelamento: pre-integracao). Nenhuma operação, campo ou enum muda; muda o que DENY significa.
recommendationsó saiDENYcom base em sanção (contraparte em lista de sanções ou com categoria de sanção devolvida pelo provedor) ou por regra de bloqueio que o próprio tenant configurou no painel (limiar de score ou combinação de regras). Os demais riscos, como misturador, darknet, valor e velocidade, saemREVIEW. Antes, score a partir de 75 ou decisão de bloqueio do provedor sem sanção também saíamDENY.- Quando a recomendação é rebaixada,
risk_levelcontinua refletindo o risco medido (por exemploCRITICAL), ereasonstraz a decisão de risco original e o motivo. Contraparte misturador recebe também o motivo da proibição legal (Res. BCB nº 520/2025, art. 90, III). - Sandbox: a carteira de alto risco
0x00000000000000000000000000000000000000b2é um misturador sem sanção e passa a devolverREVIEWcomrisk_levelCRITICAL. - Laudo KYT (
POST /vasp/kyt-report, formato JSON): carteira com match de sanções passa a sair comrecommendationDENYemverdicteconclusion, igual ao screening da mesma carteira. Antes saíaREVIEW.
8.1.0 (26/09/2026)
Seção intitulada “8.1.0 (26/09/2026)”Contrato em pré-integração (info.x-snx-congelamento: pre-integracao): ainda não há integrador em produção.
Esta versão tem mudança incompatível com a 8.0.1. Oito operações saíram do contrato. Isso só é permitido porque a linha ainda não tem integrador; depois do congelamento, uma remoção assim exigiria /api/v2. A política desta página também foi reescrita nesta versão, para registrar a fase de congelamento: até a 8.0.1 ela dizia que toda versão 8.x era compatível com a 8.0.0.
- Saíram do contrato, e do que a API serve a uma integração só de KYT, as oito leituras de ledger, que devolviam listas vazias no produto KYT e agora respondem
404:GET /vasp/balances,GET /vasp/deposits/brl,GET /vasp/deposits/brl/{id},GET /vasp/deposits/crypto,GET /vasp/deposits/crypto/{id},GET /vasp/trades,GET /vasp/withdrawalseGET /vasp/withdrawals/{id}. O contrato passa de 30 para 22 operações. - Rota inexistente ou método errado sob
/vasp, com chave válida, responde404comerror.coderoute_not_found. Antes respondia401pedindo token de sessão. Sem chave válida, a resposta continua401. - Quando a plataforma não consegue verificar a chave (falha interna na consulta), a resposta passa a ser
503comerror.codeapi_key_verification_unavailable, para repetir com backoff. Antes a mesma falha respondia401invalid_api_key, como se a chave fosse inválida. - O ambiente da chave passa a ser conferido antes do estado da conta: chave de ambiente não aceito recebe
403de ambiente mesmo quando a conta também recusaria. - Erros: toda operação declara as respostas de erro que a API realmente devolve, cada uma com schema (
401,402,403,404,429comRetry-After,500e503, e413nas que recebem corpo). Onde a mesma resposta tem mais de uma forma, o contrato lista as formas emanyOf. Correção de documentação: as formas já eram servidas; nada muda no fio. - Webhooks:
alert.createdpassa a ser emitido, uma vez por alerta criado e só depois que o alerta é gravado. Assinatura comeventsvazio passa a receber também esse evento.alert.escalatedsegue aceito na assinatura e ainda não emitido. - Limites: depois da autenticação vale o limite do tenant, 2.000 requisições por minuto, com
Retry-Afterde 1 a 60. O teto de 5.000 por hora por IP deixa de pesar sobre requisição autenticada, e a superfície/vaspdeixa de pontuar User-Agent, cabeçalhos e trechos do corpo como ataque. Detalhes em Limites de requisição. - O contrato passa a declarar a fase da linha em
info.x-snx-congelamento.
8.0.1 (25/09/2026)
Seção intitulada “8.0.1 (25/09/2026)”Correções de documentação: nada muda no que a API serve nem no que ela aceita.
- A versão do contrato passa a ser própria:
info.versiondeixa de acompanhar a especificação interna da plataforma e os SDKs, e só sobe quando este contrato muda. - Convenções: as listagens usam
limit(padrão 50, teto 200); alertas e ledger paginam comoffset, e clientes com o cursorcursor_before, devolvido emnext_cursor. A versão anterior dizia que todas as listagens usavamoffset. GET /vasp/customers: a descrição passa a dizer como o cursor funciona.next_cursorvolta vazio quando a página traz menos itens quelimit; com a página cheia ele vem preenchido, e a página seguinte pode vir vazia.- Correção de documentação:
GET /vasp/alertssempre devolveu lista emdata; o contrato agora descreve o que é servido. O schema da resposta passa a serVASPAlertListResponse, comdatacomo lista deVASPClientAlerte o blocopagination(total,limiteoffset), sem blocometa. Quem tratavadatacomo objeto seguia o contrato antigo, que não correspondia à resposta. POST /vasp/kyt-report: o limite de 120 emissões por hora é contado por IP de origem, além do limite da chave.POST /vasp/screenings: a descrição do headerIdempotency-Keyfoi corrigida na acentuação, sem mudança de regra.POST /vasp/webhooks: a descrição passa a trazer a situação de cada evento aceito emeventsnuma integração de KYT: emitido, ou aceito na assinatura e ainda não emitido. Ela também diz quewebhook.testchega só porPOST /vasp/webhooks/{id}/teste não pode ser assinado. A lista aceita emeventsnão mudou.
8.0.0 (25/09/2026)
Seção intitulada “8.0.0 (25/09/2026)”Primeira versão do contrato do cliente KYT, e a base do contrato v1. Versões anteriores da especificação descreviam a API inteira da plataforma e não eram contrato de cliente.
- O contrato publicado passa a conter só a integração de KYT por chave de API: 30 operações em 26 caminhos de
/vasp, em sete grupos (análise de transação, clientes, carteiras, ledger, alertas, webhooks e compliance). - Servidor único:
https://api.crypto.sentinexrisk.com/api/v1. - Rotas de administração e do painel, autenticadas por sessão de usuário, não fazem parte do contrato.
POST /vasp/screeningsdevolverecommendation(ALLOW,REVIEW,HOLDouDENY) e o blococlient_decision. A decisão operacional é do cliente e é registrada emPATCH /vasp/screenings/{id}/client-decision.PATCH /vasp/screenings/{id}/decisionestá marcada como obsoleta (deprecated); useclient-decision.- O contrato passa a ser publicado neste site, em
/openapi.yamle/openapi.json.