Pular para o conteúdo

Referência da API CMP

Este documento descreve como integrar com a API da Guardline Case Management Platform (CMP). Ele cobre tokens de API, a abertura de casos em cada mesa de análise (alertas de fraude, solicitações de MED, alertas de PLD e casos de onboarding), idempotência e limite de requisições, como as decisões dos analistas retornam ao sistema de origem, webhooks de saída e tratamento de erros.

O modelo de integração segue uma separação clara de responsabilidades: o motor do integrador detecta e abre o caso; a Guardline enfileira, distribui, analisa e decide. Qualquer motor de decisão, interno ou de terceiros, pode abrir casos programaticamente. A CMP então aplica filas, SLAs, distribuição, cadeias de aprovação, sessões de comitê e a trilha de auditoria exatamente como faz para os casos gerados pelos demais módulos da Suíte Guardline.

A integração envolve quatro participantes:

ParticipanteResponsabilidade
Sistema de origemDetecta um evento (alerta de transação, solicitação de MED, alerta de PLD, derivação de onboarding) e abre um caso pela API de ingestão
API CMP da GuardlineValida, deduplica, roteia o caso para uma mesa e uma fila, calcula o SLA e o distribui para um analista
Console CMP da GuardlineConsole web onde analistas, supervisores e administradores trabalham os casos e gerenciam tokens
Receptor (opcional)Endpoint do integrador que recebe webhooks de saída para eventos do workflow de PLD

Cada mesa tem seu próprio endpoint de ingestão. Todos são POST, aceitam application/json e autenticam com um token de API com escopo restrito àquela mesa.

MesaEndpointEscopo do tokenIdentificador do caso
Fraude/api/v1/ingest/fraudeingest:fraudeexternal_id
MED (Mecanismo Especial de Devolução)/api/v1/ingest/medingest:medid, event_id, notification_id ou med_id
PLD (prevenção à lavagem de dinheiro)/api/v1/ingest/pldingest:pldalerta_externo_id
Onboarding, pessoas físicas (KYC) e pessoas jurídicas (KYB)/api/v1/ingest/kycingest:kycexecution_id (envelope de onboarding) ou case_id (payload genérico)

Todas as demais rotas da API CMP (/api/v1/cases, /api/v1/queues, /api/v1/users e assim por diante) pertencem ao console e são autenticadas pelo cookie de sessão do analista. Essas rotas não fazem parte do contrato de integração e não estão documentadas aqui, com exceção dos endpoints de administração de tokens em Administração de tokens.

Todas as chamadas de API seguem o padrão REST sobre HTTPS com payloads JSON.

AmbienteURL base
Sandboxhttps://{instance}.cmp.dev.guardline.com.br
Produçãohttps://{instance}.cmp.prod.guardline.com.br

O valor {instance} é provisionado durante a configuração do integrador e identifica a infraestrutura dedicada. Cada instância tem seu próprio banco de dados e sua própria aplicação, isolados. Um token emitido em uma instância autentica apenas naquela instância.

Requisições HTTP são rejeitadas. HTTPS com TLS 1.2 ou superior é obrigatório em todos os ambientes.

Toda chamada de ingestão exige o cabeçalho X-API-Key com um token de API.

X-API-Key: cmp_e188905ec47a80ec035fe31a3264bf1a5f9231f1353ea24717cf311740305f11

Os tokens têm o formato cmp_ seguido de 64 caracteres hexadecimais. São criados por um administrador da CMP, no console (tela de tokens de API) ou pelos endpoints de administração de tokens. O valor em texto puro é exibido apenas uma vez, na resposta de criação. Internamente, a CMP armazena o hash SHA-256 do token junto com um prefixo de exibição (os 12 primeiros caracteres, como cmp_e188905e), para que os administradores reconheçam um token sem expô-lo.

Cada token carrega:

AtributoDescrição
labelNome em texto livre, por exemplo fpp-producao ou onp-webhook-kyc
scopeA mesa em que o token pode escrever. Consulte Escopos
rate_limit_max, rate_limit_window_secondsLimite de requisições por token. O padrão é 60 requisições a cada 60 segundos
expires_in_daysExpiração opcional. 0 (o padrão) significa que o token nunca expira

Um problema de credencial sempre responde 401 ou 403, nunca 400:

StatusMensagemCausa
401missing api keyO cabeçalho X-API-Key não foi enviado ou está vazio
401invalid api keyO token é desconhecido, foi desativado, foi excluído ou expirou
403token scope not authorized for this endpointO token existe, mas seu escopo não cobre o endpoint

Um 400 significa que o token foi aceito e o corpo da requisição foi rejeitado, portanto reemitir o token não resolve o problema.

Toda chamada rejeitada (chave ausente, chave inválida, escopo incorreto, limite de requisições) é registrada na trilha de auditoria da CMP com o IP de origem, o caminho e o motivo. As ingestões bem-sucedidas também são registradas, com o corpo completo.

EscopoEndpoints permitidos
ingest:fraudePOST /api/v1/ingest/fraude
ingest:medPOST /api/v1/ingest/med
ingest:pldPOST /api/v1/ingest/pld
ingest:kycPOST /api/v1/ingest/kyc (casos KYC e KYB compartilham este endpoint e este escopo)
ingestOs quatro endpoints de ingestão

Use o escopo mais restrito que cubra o sistema de origem. O escopo genérico ingest existe para ferramentas e não deve ser emitido para um motor em produção que escreve em uma única mesa. Um token criado sem escopo explícito recebe o escopo genérico ingest, que é aceito nos quatro endpoints de mesa. As strings de escopo não são validadas na criação, portanto um erro de digitação gera um token que é rejeitado em todos os endpoints.

O limite de requisições é aplicado por token, por endpoint de mesa e por réplica da API, em uma janela fixa. O limite e a janela são atributos do token (rate_limit_max e rate_limit_window_seconds, com padrão de 60 requisições a cada 60 segundos) e são escolhidos pelo administrador no momento da criação. Cada rota de ingestão conta a própria janela e cada réplica mantém os próprios contadores em memória, portanto o teto efetivo é maior que o número configurado quando várias réplicas atendem ao tráfego. Janelas acima de 120 segundos não são confiáveis: uma janela é descartada dois minutos após o último uso, independentemente de rate_limit_window_seconds. Dimensione o limite para o pico do sistema de origem, lembrando que retries com backoff no lado do remetente podem gerar rajadas.

Quando o limite é excedido, a API responde 429 com a mensagem ingest rate limit exceeded. Aguarde o fim da janela e tente novamente; a requisição não foi processada.

O corpo da requisição é limitado a 1 MB por padrão, e o limite é configurável por instância. Um corpo acima do limite é rejeitado com 413. Decida os retries pelo status HTTP, e não pelo campo code: atualmente um corpo acima do limite informa code: INTERNAL_ERROR junto com o 413.

O cabeçalho opcional X-Tenant-Slug identifica o tenant do sistema de origem e é registrado na trilha de auditoria apenas nas chamadas rejeitadas, não em uma ingestão bem-sucedida. Quando omitido, assume o valor default. Ele não altera o roteamento: a instância é a fronteira de isolamento.

Os endpoints de ingestão retornam o corpo do recurso diretamente, sem envelope. O formato é específico de cada endpoint e está documentado em cada seção; as três mesas genéricas (fraude, MED, onboarding) compartilham este:

{
"case_id": "2ca0bd66-0ef9-44e6-9b47-6816264dd779",
"external_id": "fpp-case-001",
"created": true
}

Os erros usam um único envelope em todos os endpoints:

{
"error": true,
"message": "external_id é obrigatório",
"code": "BAD_REQUEST",
"request_id": "5c1e8f2a-7b3d-4c9e-a1f0-2d6b8e4a9c7f"
}
CampoDescrição
errorSempre true em uma resposta de erro
messageMotivo legível por humanos. As mensagens de validação estão em português ou em inglês, dependendo da mesa
codeCódigo estável legível por máquina. Consulte Códigos de erro
request_idIdentificador de correlação, também retornado no cabeçalho de resposta X-Request-ID. Informe-o ao acionar o suporte

Fora de produção, o envelope também traz um campo details com o erro interno bruto. Em produção, o campo é omitido.

Todo endpoint de ingestão é idempotente sobre uma chave natural escolhida pelo sistema de origem, com escopo na mesa:

MesaChave natural
Fraudeexternal_id
MEDid, event_id, notification_id ou med_id (o primeiro presente); caso contrário, o SHA-256 do corpo bruto, armazenado e retornado como sha256: seguido do hash
PLDalerta_externo_id
Onboardingexecution_id (envelope de onboarding) ou case_id (payload genérico de KYC)

A primeira chamada para uma chave cria o caso e responde 201. Qualquer chamada posterior com a mesma chave responde 200 com created: false (ou is_new_case: false na mesa de PLD) e o identificador do caso existente. Nada é sobrescrito: o caso é imutável após a criação e o trabalho do analista nunca é substituído por um reenvio. Isso torna os endpoints seguros para repetir a chamada após um timeout de rede, sem gerar trabalho duplicado para a mesa.

A janela de idempotência é ilimitada: a chave permanece única durante todo o tempo de vida da mesa.

POST /api/v1/ingest/fraude

Escopo: ingest:fraude. Abre um caso na mesa de Fraude a partir de um alerta de transação produzido por um motor de detecção de fraude (a FPP da Guardline ou um motor de terceiros).

O corpo é um objeto JSON. Apenas três campos são obrigatórios; todo o restante enriquece o caso. Os nomes de chave alternativos aceitos para o mesmo campo estão listados na coluna de aliases. O corpo completo é preservado como payload do caso, portanto as chaves que não estão listadas aqui são mantidas e ficam visíveis para o analista, ainda que não sejam indexadas.

CampoTipoObrigatórioAliasesDescrição
external_idstringsimid, event_idIdentificador único do alerta no sistema de origem. Chave de idempotência
subject_documentstringsimdocumentoCPF ou CNPJ do cliente investigado. Diferentemente da mesa de PLD, o formato não é validado: a pontuação não é removida e a quantidade de dígitos não é verificada, portanto o valor é armazenado exatamente como enviado e deve ser normalizado por quem chama
transaction_amountnumbersimamount, valorValor em BRL, deve ser maior que zero. Armazenado em centavos
subject_namestringnãocliente_nome, nomeNome do cliente
counterparty_namestringnãocontraparte_nomeNome da contraparte (beneficiário)
transaction_typestringnãotipo_transacaoTipo da transação, em minúsculas. O padrão é pix
risk_levelstringnãoriscoApenas low, medium, high e critical são reconhecidos. Derivado de score quando ausente ou vazio; qualquer outro valor deixa o caso sem nível de risco
scoreintegernãoScore do motor na escala de 0 a 1000. Consulte Score, risco e prioridade
priorityintegernão0 a 9, quanto menor, mais urgente. O padrão é 3. Valores fora da faixa são ajustados ao limite
sla_deadlinestring (RFC 3339)nãoPrazo de SLA explícito. Quando ausente, o prazo vem da política de SLA configurada para a mesa, e o caso é criado sem prazo quando nenhuma política se aplica. Um valor que não pode ser interpretado é ignorado silenciosamente e a política da mesa se aplica em seu lugar; nenhum 400 é retornado
fraud_analysisobjectnãoExplicação completa da decisão e contexto do cliente. Consulte O bloco fraud_analysis

A mesa de Fraude espera o score do motor na escala da FPP (0 a 1000). A CMP armazena score / 10, limitado a 100, no caso, para que filas e dashboards compartilhem uma única escala entre as mesas. A divisão é uma divisão inteira, portanto o resultado é truncado e não arredondado: 999 é armazenado como 99. O valor original permanece no payload do caso.

Quando risk_level está ausente ou vazio, ele é derivado do score bruto:

Score (0 a 1000)risk_level derivado
950 ou maiscritical
850 a 949high
700 a 849medium
abaixo de 700low

Quando nem risk_level nem score são enviados, o caso é criado com risk_level = medium.

A derivação ocorre apenas quando o campo está ausente ou vazio. Somente os quatro valores acima são reconhecidos, e um valor não vazio que não seja reconhecido pula a derivação e deixa o caso sem nenhum nível de risco, portanto envie um dos quatro valores ou omita o campo por completo.

priority ordena o caso na fila e alimenta o motor de distribuição junto com o score. É independente do nível de risco.

fraud_analysis é o que o painel de análise de fraude do analista renderiza. Ele é armazenado literalmente e fornece a explicação do workflow (estágios, políticas, regras e suas contribuições), o detalhe da transação com dispositivo e localização, o perfil do cliente com baselines comportamentais e transações recentes, comparações de anomalias e as linhas do tempo do cliente e da contraparte. Envie-o em todo alerta para que o painel reflita este caso.

{
"explanation": {
"workflow_id": "wf-pix-out",
"workflow_name": "pix_out_standard",
"total_score": 780,
"decision": "REVIEW",
"review_threshold": 600,
"block_threshold": 900,
"stages_executed": 3,
"stages_total": 3,
"early_terminated": false,
"execution_time_ms": 45,
"stages_results": [
{
"stage_id": "st-velocity",
"stage_name": "velocity",
"score": 320,
"should_block": false,
"policies_results": [
{
"policy_id": "pol-velocity-amount",
"policy_name": "amount_vs_baseline",
"contribution": 200,
"score_weight": 0.4,
"rules_results": [
{
"rule_id": "rule-amount-4x",
"rule_name": "amount_over_4x_avg",
"passed": false,
"score": 300,
"score_contribution": 150,
"category": "velocity"
}
]
}
]
}
]
},
"transaction": {
"id": "tx-9f1c",
"amount": 35407.28,
"currency": "BRL",
"type": "TED",
"channel": "internet_banking",
"direction": "OUT",
"account_id": "acc-1234",
"counterpart_document": "04523967199",
"counterpart_name": "Empresa Suspeita LTDA",
"created_at": "2026-04-02T14:32:10Z",
"device": { "type": "mobile", "os": "Android 14", "is_new": false, "is_vpn": false, "is_proxy": false },
"location": { "city": "São Paulo", "state": "SP", "country": "BR", "ip": "189.40.72.33" }
},
"customer": {
"profile": {
"id": "cust-7788",
"name": "Ana Sophia Lopes",
"document_type": "CPF",
"document_number": "61589720458",
"customer_type": "person",
"customer_since": "2019-03-15",
"score": 100,
"kyc_status": "approved",
"risk_rating": "low",
"is_pep": false,
"sanctions_found": false,
"previous_fraud_count": 0
},
"baselines": [
{
"period_days": 90,
"transaction_type": "ALL",
"amount_avg": 7523.45,
"amount_stddev": 10724.0,
"amount_p95": 18000.0,
"tx_count": 23,
"unique_counterparts": 7,
"typical_hours": [9, 10, 11, 14, 15, 16, 17],
"typical_days": [1, 2, 3, 4, 5]
}
],
"recent_transactions": []
},
"comparisons": [
{ "label": "Valor", "is_anomalous": true, "severity": "high", "value": "4.7x", "detail": "R$ 35.407,28 vs média R$ 7.523,45" }
],
"network_stats": { "unique_payers": 8, "transaction_count": 12, "active_days": 45, "avg_transaction": 22500.0 },
"customer_timeline": { "account_id": "acc-1234", "transactions": [], "aggregates": [] },
"counterpart_timeline": { "counterpart_document": "04523967199", "transactions": [], "aggregates": [] }
}

Todos os sub-blocos são opcionais. Envie o que o motor tiver: um sub-bloco que não for enviado simplesmente não é renderizado, enquanto um sub-bloco cujos tipos de campo não correspondem ao schema é descartado, portanto respeite o formato documentado.

Alerta mínimo:

Terminal window
curl -X POST https://{instance}.cmp.prod.guardline.com.br/api/v1/ingest/fraude \
-H "Content-Type: application/json" \
-H "X-API-Key: cmp_..." \
-d '{
"external_id": "fpp-case-001",
"subject_document": "12345678901",
"transaction_amount": 15000.50
}'

Alerta completo:

{
"external_id": "fpp-case-002",
"subject_name": "Ana Sophia Lopes",
"subject_document": "61589720458",
"counterparty_name": "Empresa Suspeita LTDA",
"transaction_type": "ted",
"transaction_amount": 35407.28,
"risk_level": "high",
"priority": 2,
"score": 810,
"sla_deadline": "2026-04-03T14:32:10Z",
"fraud_analysis": { "explanation": { "...": "..." }, "transaction": { "...": "..." }, "customer": { "...": "..." } }
}

201 Created, caso novo:

{
"case_id": "2ca0bd66-0ef9-44e6-9b47-6816264dd779",
"external_id": "fpp-case-002",
"created": true
}

200 OK, o external_id já existe na mesa de Fraude:

{
"case_id": "2ca0bd66-0ef9-44e6-9b47-6816264dd779",
"external_id": "fpp-case-002",
"created": false
}

O novo caso entra na mesa de Fraude com status new, status de negócio aguardando_analise e um item de trabalho enfileirado. O motor de distribuição o atribui a um analista disponível da fila de entrada.

StatusmessageCausa
400empty bodyNenhum corpo foi enviado
400invalid jsonO corpo não é um JSON válido
400external_id é obrigatórioIdentificador ausente
400subject_document é obrigatórioDocumento do cliente ausente
400transaction_amount deve ser maior que zeroValor ausente, não numérico ou não positivo
401missing api key, invalid api keyConsulte Tokens de API
403token scope not authorized for this endpointO escopo do token não é ingest:fraude nem ingest
429ingest rate limit exceededLimite por token excedido
POST /api/v1/ingest/med

Escopo: ingest:med. Abre um caso na mesa de MED a partir de uma solicitação do Mecanismo Especial de Devolução (MED) recebida pela instituição.

A mesa de MED foi a primeira mesa da plataforma e aceita o conjunto mais amplo de aliases de chave, para que exportações já existentes do backoffice de PIX possam ser encaminhadas com transformação mínima. O corpo completo é preservado como payload do caso.

CampoTipoObrigatórioAliasesDescrição
valor_solicitadonumbersimamount, valorValor solicitado para devolução, em BRL, maior que zero. Armazenado em centavos
idstring ou numberrecomendadoevent_id, notification_id, med_idIdentificador da solicitação de MED no sistema de origem. Chave de idempotência. Quando todos estão ausentes, é usado o SHA-256 do corpo bruto, armazenado e retornado como sha256: seguido do hash, de modo que um reenvio idêntico byte a byte continua sendo deduplicado. O hash do corpo não sobrevive a nenhuma mudança na serialização (ordem das chaves, formatação dos números, um timestamp presente no payload), portanto ele não substitui o envio de um identificador real
request_idstringnãomed_request_id, idNúmero do protocolo MED exibido ao analista. Quando ausente, ele assume um valor derivado de uma cópia reserializada do payload, que não necessariamente coincide com o external_id retornado a quem chama, portanto envie-o explicitamente
requested_atstring (RFC 3339)nãocreated_at, event_atQuando a solicitação foi aberta. O padrão é o horário da ingestão
motivostringnãoreason_code, reason, tipogolpe (padrão), fraude ou erro_operacional. Valores desconhecidos assumem golpe
statusstringnãomed_statusaberta (padrão), em_analise, aguardando_instituicao, aprovado, negado ou recusado. Valores desconhecidos assumem aberta
prazo_limite_atstring (RFC 3339)nãodeadline_atPrazo regulatório de resposta da solicitação de MED
recebedoraobjectnãorecipient, counterpartyInstituição recebedora: { "nome": "...", "ispb": "..." }. Em recebedora, apenas nome é lido; name funciona em recipient e counterparty. Chaves planas recebedora_nome, counterparty_name e recebedora_ispb também são aceitas. Quando nenhum nome de instituição recebedora pode ser resolvido, o caso é armazenado com um nome placeholder
recebedora_respondeubooleannãoIndica se a instituição recebedora já respondeu
valor_devolvidonumbernãoValor já devolvido, em BRL
data_devolucao_atstring (RFC 3339)nãoQuando a devolução ocorreu
subject_namestringnãocliente_nome, nomeNome do cliente
subject_documentstringnãocliente_documento, documentoCPF ou CNPJ do cliente
transaction_typestringnãotipo_transacaoO padrão é pix
risk_levelstringnãorisklow, medium, high ou critical. Valores desconhecidos são ignorados
scoreintegernão0 a 100. Diferentemente da mesa de Fraude, o score da mesa de MED não é normalizado: ele já deve estar na escala de 0 a 100, e valores fora dessa faixa são rejeitados
priorityintegernão0 a 9, quanto menor, mais urgente. O padrão é 3
Terminal window
curl -X POST https://{instance}.cmp.prod.guardline.com.br/api/v1/ingest/med \
-H "Content-Type: application/json" \
-H "X-API-Key: cmp_..." \
-d '{
"id": "MED-2026-000123",
"requested_at": "2026-08-20T13:05:00Z",
"valor_solicitado": 4200.00,
"motivo": "golpe",
"status": "aberta",
"prazo_limite_at": "2026-08-27T13:05:00Z",
"subject_name": "Carlos Eduardo Nunes",
"subject_document": "47055107806",
"recebedora": { "nome": "Banco Exemplo S.A.", "ispb": "12345678" },
"priority": 2
}'

201 Created quando o caso é novo, 200 OK com created: false quando o identificador já existe na mesa de MED:

{
"case_id": "8d1b3f4e-2a6c-4d7e-9b0a-1c2d3e4f5a6b",
"external_id": "MED-2026-000123",
"created": true
}
StatusmessageCausa
400empty body, invalid jsonRequisição malformada
400missing or invalid valor_solicitadoValor ausente, não numérico ou não maior que zero
401missing api key, invalid api keyConsulte Tokens de API
403token scope not authorized for this endpointO escopo do token não é ingest:med nem ingest
429ingest rate limit exceededLimite por token excedido
POST /api/v1/ingest/pld

Escopo: ingest:pld. Abre ou enriquece um caso na mesa de PLD (prevenção à lavagem de dinheiro) a partir de um alerta transacional produzido por um motor de monitoramento. A mesa de PLD difere das demais em dois pontos: alertas de um cliente que já tem um caso aberto são consolidados nesse caso em vez de abrir um novo, e movimentações em espécie iguais ou superiores ao limiar regulatório são sinalizadas como COE automática (comunicação de operação em espécie), que pula a triagem.

CampoTipoObrigatórioAliasesDescrição
alerta_externo_idstringsimIdentificador único do alerta no sistema de origem. Chave de idempotência. Limitado a 100 caracteres; um valor mais longo atualmente falha como erro de servidor, e não como erro de validação, portanto respeite o limite
cpf_cnpjstringsimCPF (11 dígitos) ou CNPJ (14 dígitos) do cliente investigado. A pontuação é removida antes da validação
tipo_alertastringsimCódigo do tipo de alerta, sem diferenciar maiúsculas de minúsculas. Veja Tipos de alerta
subject_namestringrecomendadocliente_nome, nomeNome do cliente
score_risconumberrecomendadoscoreScore de risco. São aceitas tanto a escala de 0 a 100 quanto a de 0 a 1000; valores acima de 100 são divididos por 10
valor_totalnumberrecomendadovalorValor total da movimentação, em BRL. Usado pela regra de COE
valor_total_centavosintegernãovalor_centavosO mesmo valor em centavos. Tem precedência sobre valor_total quando ambos estão presentes
tipologia_sugeridastring[]nãoCódigos de tipologia sugeridos pelo motor, por exemplo ["PIX001", "EST001"]
dados_clienteobjectnãoContexto livre do cliente (renda declarada, atividade, cidade, estado). Armazenado literalmente e exibido no dossiê
dados_transacionaisobjectnãoContexto transacional livre (quantidade de operações, período, canais). Armazenado literalmente
contrapartesarraynãoContrapartes envolvidas. Armazenadas literalmente
is_coebooleannãoForça a classificação de COE automática independentemente do tipo e do valor
priorityintegernão0 a 9, quanto menor, mais urgente. O padrão é 3. Uma COE automática sempre fica com prioridade 1
fpp_source_urlstringnãoDeep link de volta para o alerta no sistema de origem, exibido no dossiê

tipo_alerta deve ser um dos códigos abaixo. Um código desconhecido é rejeitado com 404.

CódigoDescrição
pixTransferência PIX
tedTransferência TED
docTransferência DOC
boletoPagamento de boleto
especieMovimentação em espécie (cédulas). O único tipo elegível para a regra de COE automática
cambioOperação de câmbio
cartaoOperação com cartão
depositoDepósito
saqueSaque
transferenciaTransferência genérica entre contas
outroQualquer outra movimentação

Cada alerta passa por quatro etapas em uma única transação:

  1. Idempotência. Se já existe um alerta com o mesmo alerta_externo_id, a API responde 200 com is_new_case: false e consolidated_into preenchido com o número do caso que contém o alerta original. Nenhum dado de caso ou de alerta é gravado; o reenvio é registrado na trilha de auditoria. Duas chamadas que carregam o mesmo identificador e chegam no mesmo instante são uma situação diferente: uma delas perde a corrida no índice único e recebe 409 com o código ALREADY_EXISTS, o que pode ser tratado com segurança como uma duplicata.
  2. Detecção de COE. O alerta é uma COE automática quando is_coe é true, ou quando tipo_alerta é especie e o valor total é igual ou superior a R$ 50.000,00. Uma COE automática sempre cria um novo caso (nunca é consolidada), começa no status PLD pendente_geracao_xml com prioridade 1 e é projetada como decided / aprovado no status genérico do caso, de modo que apareça como pronta para a etapa de comunicação ao COAF.
  3. Consolidação. Quando o alerta não é uma COE e o mesmo cpf_cnpj já tem um caso de PLD ativo (qualquer status PLD diferente de arquivado_triagem, arquivado, comunicado_coaf, retificado ou cancelado), o alerta é anexado a esse caso. A API responde 200 com is_new_case: false e consolidated_into preenchido com o número do caso existente. O analista vê o novo alerta no dossiê do caso em que já está trabalhando. Um alerta de COE sempre abre o próprio caso e nunca é consolidado em um caso ativo existente. A COE também exige que o sistema de origem marque o alerta como operação em espécie (tipo_alerta igual a especie ou a flag explícita is_coe): o limiar de valor sozinho não a aciona.
  4. Novo caso. Caso contrário, um novo caso de PLD é criado com status new, status de negócio aguardando_analise, status PLD novo, prazo de seleção de 45 dias (prazo_selecao) e um número de caso legível no formato PLD-YYYY-NNNNN. A API responde 201.

Alerta mínimo:

{
"alerta_externo_id": "ALR-2026-000981",
"cpf_cnpj": "12345678901",
"tipo_alerta": "pix"
}

Alerta recomendado:

Terminal window
curl -X POST https://{instance}.cmp.prod.guardline.com.br/api/v1/ingest/pld \
-H "Content-Type: application/json" \
-H "X-API-Key: cmp_..." \
-d '{
"alerta_externo_id": "ALR-2026-000982",
"cpf_cnpj": "321.987.654-00",
"tipo_alerta": "pix",
"subject_name": "Marcia Helena Souza",
"score_risco": 82,
"valor_total": 47500,
"tipologia_sugerida": ["PIX001"],
"dados_cliente": {
"cidade": "São Paulo",
"uf": "SP",
"renda_declarada": 4500,
"atividade": "Vendedora autônoma"
},
"dados_transacionais": {
"qtd_operacoes": 18,
"periodo_dias": 5
},
"fpp_source_url": "https://fpp.example.com/alerts/ALR-2026-000982"
}'

Movimentação em espécie que dispara uma COE automática:

{
"alerta_externo_id": "ALR-2026-000990",
"cpf_cnpj": "12345678000199",
"tipo_alerta": "especie",
"subject_name": "Acme Serviços LTDA",
"valor_total_centavos": 7500000
}

201 Created, novo caso:

{
"case_id": "2ca0bd66-0ef9-44e6-9b47-6816264dd779",
"case_pld_detail_id": "21be5573-402d-49d8-ab8d-461cb27f60b7",
"numero_caso": "PLD-2026-00021",
"is_new_case": true,
"is_coe_automatica": false,
"alerta_externo_id": "ALR-2026-000982"
}

200 OK, alerta duplicado ou alerta consolidado em um caso ativo do mesmo cliente:

{
"case_id": "5378d55e-f23f-4fd8-a2ce-1a28e9399535",
"case_pld_detail_id": "b039a7cc-2a32-4dec-a6f2-5b7d643c82d3",
"numero_caso": "PLD-2026-00006",
"is_new_case": false,
"is_coe_automatica": false,
"consolidated_into": "PLD-2026-00006",
"alerta_externo_id": "ALR-2026-000983"
}
CampoDescrição
case_idUUID do caso que contém o alerta
case_pld_detail_idUUID do registro de detalhe de PLD desse caso
numero_casoNúmero do caso legível, o identificador que os operadores citam
is_new_casetrue quando um caso foi criado por esta chamada
is_coe_automaticatrue quando o caso é uma COE automática. Preenchido apenas quando esta chamada cria ou consolida o caso: uma repetição idempotente simples retorna false mesmo para um caso de COE, portanto leia esse campo na resposta da criação, e não em uma repetição
consolidated_intoPresente apenas quando is_new_case é false: o número do caso que absorveu o alerta, seja porque o alerta_externo_id já era conhecido, seja porque o cliente tinha um caso ativo
alerta_externo_idEco do identificador da requisição

Para distinguir as duas situações de 200, compare numero_caso com o que o sistema de origem esperava: uma duplicata retorna o caso do alerta original; uma consolidação retorna um caso que foi aberto por um alerta diferente.

StatusmessageCausa
400empty body, invalid jsonRequisição malformada
400alerta_externo_id is requiredIdentificador ausente
400cpf_cnpj must be a valid 11 or 14-digit documentDepois da remoção dos caracteres não numéricos, o documento não tem 11 nem 14 caracteres
400tipo_alerta is requiredTipo de alerta ausente
404pld_alert_type "xyz" not foundtipo_alerta não é um dos tipos de alerta; a mensagem cita o valor que foi enviado
401missing api key, invalid api keyVeja Tokens de API
403token scope not authorized for this endpointO escopo do token não é ingest:pld nem ingest
429ingest rate limit exceededLimite por token excedido
POST /api/v1/ingest/kyc

Escopo: ingest:kyc. Abre um caso nas mesas de onboarding: Cadastro PF (KYC, pessoas físicas) ou Cadastro PJ (KYB, empresas). Não existe uma rota /ingest/kyb separada; a mesa é escolhida pelo flow_type do payload.

O endpoint aceita dois formatos de corpo, diferenciados pelo campo event_type:

FormatoQuandoDiscriminador
Envelope de onboardingO caso vem da ONP da Guardline ou de um motor de onboarding que segue o mesmo contrato. Suporta os fluxos KYC, KYC menor de idade, representante legal e KYB, e devolve as decisões terminais para reconciliaçãoevent_type é cmp.case.review, cmp.case.approved ou cmp.case.rejected
Payload genérico de KYCUm motor de decisão de terceiros envia sua análise completa de KYC de uma pessoa físicaevent_type ausente ou com qualquer outro valor

Os dois formatos respondem com o mesmo corpo { case_id, external_id, created }.

Além do token de API, o endpoint pode exigir uma assinatura HMAC. A camada de assinatura é habilitada por instância, quando um segredo compartilhado é provisionado durante a configuração da integração; até lá, apenas o X-API-Key é exigido. Quando habilitada, a assinatura é verificada antes do token de API.

CabeçalhoValor
X-Guardline-TimestampTempo Unix em segundos (inteiro) no momento da assinatura
X-Guardline-SignatureHMAC-SHA256 de {timestamp}.{body} em hexadecimal minúsculo

Procedimento de assinatura:

  1. Serialize o corpo uma única vez. Os bytes enviados devem ser exatamente os bytes assinados; não serialize novamente nem reformate o conteúdo depois de assinar.
  2. Concatene o timestamp, um ponto literal e o corpo bruto: {timestamp}.{body}.
  3. Calcule o HMAC-SHA256 dessa string com o segredo compartilhado e codifique o digest em hexadecimal.
Terminal window
BODY='{"event_type":"cmp.case.review","execution_id":"...","flow_type":"kyc", "...":"..."}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -r | cut -d' ' -f1)
curl -X POST https://{instance}.cmp.prod.guardline.com.br/api/v1/ingest/kyc \
-H "Content-Type: application/json" \
-H "X-API-Key: $TOKEN" \
-H "X-Guardline-Timestamp: $TS" \
-H "X-Guardline-Signature: $SIG" \
--data-raw "$BODY"

O timestamp deve estar dentro de 5 minutos do relógio do servidor (a tolerância é configurável por instância). Falhas de assinatura respondem 401 com um dos valores missing signature, missing timestamp, malformed timestamp, stale timestamp, malformed signature ou invalid signature.

Este é o mesmo formato que a ONP da Guardline usa nos seus webhooks de saída, portanto um integrador que já verifica os webhooks da ONP pode reaproveitar a rotina para assinar as chamadas à CMP.

O envelope é o corpo que a ONP da Guardline envia à CMP quando uma execução de onboarding é encaminhada para análise manual e, novamente, quando a execução chega a uma decisão terminal. A referência da API da ONP descreve o lado produtor; esta seção descreve o que a CMP espera e faz.

event_typeEfeito
cmp.case.reviewCria o caso e o coloca na fila da mesa. Este é o único evento que cria um caso. Um reenvio para o mesmo execution_id responde 200 com created: false
cmp.case.approvedReconcilia uma aprovação terminal em um caso criado anteriormente por um review. Se o caso ainda não tem decisão, a aprovação é registrada como a decisão. Nunca cria um caso
cmp.case.rejectedO mesmo que o anterior, para uma reprovação. O código de decisão kyc_reject_* (ou kyb_reject_*) é escolhido a partir de rejection_reasons

Um evento terminal para um execution_id que nunca produziu um review responde 200 com case_id vazio e created: false: a execução foi decidida automaticamente pelo motor, nunca chegou à mesa e a CMP deliberadamente não cria um caso em fila para ela. Um evento terminal nunca sobrescreve uma decisão que um analista já registrou.

CampoTipoObrigatórioDescrição
event_typestringsimVeja Semântica dos eventos
execution_idstringsimIdentificador da execução de onboarding. Armazenado como o external_id do caso e usado como chave de idempotência
flow_typestringsimkyc (pessoa física adulta), kyc_minor (menor de idade com representante legal), kyc_representative (a própria execução do representante, analisada como um caso à parte) ou kyb (empresa). kyb roteia para a mesa Cadastro PJ, os demais para Cadastro PF
subjectobjectsimVeja abaixo
case_envelopeobjectsimVeja abaixo
event_idstringnãoIdentificador do evento no lado produtor, armazenado junto com o caso
fired_atstring (RFC 3339)nãoQuando o produtor emitiu o evento
tenant_idstringnãoTenant do produtor, informativo
flow_id, flow_group_codestringnãoFluxo e grupo de fluxo da execução, informativos
edd_flaggedbooleannãoA execução exige diligência reforçada. Exibido ao analista
rejection_reasonsstring[]nãoMotivos em texto livre por trás de uma reprovação. Usados para classificar o código de decisão da reprovação
derivation_reasonsobject[]nãoPor que o motor encaminhou o caso para análise manual: { "code", "label_ptbr", "severity", "source", "detail" }. Exibido literalmente no dossiê
representativeobjectnãoSomente kyc_minor: { "execution_id", "status" } da execução do representante legal
guardian_typestringnãoSomente kyc_minor: parent, mother, father ou other
representativesobject[]nãoSomente kyb: os representantes legais da empresa, { "execution_id", "status", "name", "flag", "document", "document_type" }. flag é true quando o representante foi reprovado ou expirou. Entradas sem execution_id ou sem name são descartadas

subject:

CampoTipoObrigatórioDescrição
documentstringapenas em eventos terminaisCPF ou CNPJ, apenas dígitos (a pontuação é removida). Um cmp.case.review pode chegar com o documento vazio quando a execução foi encaminhada antes de a etapa de identidade ser concluída; o analista resolve a identidade na mesa
document_typestringnãocpf ou cnpj
namestringnãoNome do sujeito, exibido na fila
email, phone, birth_datestringnãoCapturados no payload do caso

case_envelope:

CampoTipoObrigatórioDescrição
prioritystringsimP0, P1, P2 ou P3, quanto menor, mais urgente. Mapeado para a prioridade do caso de 0 a 3. Qualquer outro valor é rejeitado
case_statusstringnãoStatus do motor: approved, rejected, blocked, escalated ou outro. Define a decisão de workflow exibida ao analista (veja o mapeamento abaixo)
decision_codestringnãoDecisão do motor: approved, rejected ou pending_review (as formas curtas approve, reject e review também são aceitas). Define a decisão terminal da CMP em cmp.case.approved / cmp.case.rejected
risk_levelstringnãolow, medium, high ou critical, sem diferenciar maiúsculas e minúsculas. Valores desconhecidos são ignorados
total_scorenumbernãoScore do motor. Armazenado como o score do workflow e, limitado a 0 a 100, como o score do caso usado pelas filas
sla_deadline_at, completed_at, expires_atstring (RFC 3339)nãoTimestamps do produtor. completed_at passa a ser o momento da decisão em um evento terminal
OrigemAtributo do casoRegra
case_envelope.case_statusDecisão de workflow exibida na mesaapproved vira ALLOW; rejected e blocked viram BLOCK; qualquer outro valor vira REVIEW
case_envelope.decision_code + rejection_reasonsCódigo de decisão terminalapproved registra kyc_approve_onboarding (kyb_approve_onboarding para empresas). rejected registra kyc_reject_fraud_suspicion quando os motivos mencionam fraud, suspicious ou scam; kyc_reject_document_invalid quando mencionam document, invalid_doc, expired ou illegible; kyc_reject_compliance nos demais casos. pending_review não registra nada: o analista decide
case_envelope.priorityPrioridade do casoP0 a P3 mapeiam para 0 a 3
case_envelope.risk_levelNível de risco do casoConvertido para minúsculas; valores desconhecidos deixam o nível de risco indefinido
case_envelope.total_scoreScore do casoArredondado e limitado a 0 a 100
subject.name, subject.documentColunas da filaExibidas na listagem da mesa

Os casos criados por um cmp.case.review entram na mesa com status new, status de negócio aguardando_analise e um item de trabalho em fila, exatamente como nas demais mesas. No momento da ingestão apenas o envelope é persistido; o dossiê completo (documentos, biometria, resultados dos parceiros, árvore de decisão) é buscado na ONP sob demanda quando o analista abre o caso.

Caso KYC encaminhado para análise manual:

{
"event_id": "01HZX5K7TPMJ9R2QXYZABCDEF1",
"event_type": "cmp.case.review",
"fired_at": "2026-05-25T17:00:00Z",
"tenant_id": "default",
"execution_id": "7b5c3d22-3e5f-4a7b-93b8-c6f5a2d4a4e2",
"flow_id": "61000000-0000-0000-0000-000000000003",
"flow_type": "kyc_minor",
"flow_group_code": "Guardline KYC Menor",
"case_envelope": {
"case_status": "escalated",
"decision_code": "pending_review",
"risk_level": "medium",
"total_score": 480,
"priority": "P1",
"sla_deadline_at": "2026-05-26T17:00:00Z",
"completed_at": "2026-05-25T17:00:00Z",
"expires_at": "2026-06-25T17:00:00Z"
},
"subject": {
"document": "11122233344",
"document_type": "cpf",
"name": "Pedro Henrique Silva",
"email": "pedrinho@example.com",
"phone": "+5511977665544",
"birth_date": "2010-07-08"
},
"representative": {
"execution_id": "6c4d2e11-4a6b-5c8d-04c9-d7e6b3f5b5a3",
"status": "completed"
},
"rejection_reasons": [],
"derivation_reasons": [
{ "code": "biometrics_not_completed", "label_ptbr": "Biometria não concluída", "severity": "medium", "source": "onp" }
],
"edd_flagged": false,
"guardian_type": "mother"
}

Caso KYB encaminhado para análise manual:

{
"event_id": "6f7d1e10-2a3b-4c5d-8e9f-0a1b2c3d4e5f",
"event_type": "cmp.case.review",
"fired_at": "2026-07-17T17:00:00Z",
"tenant_id": "default",
"execution_id": "9a1f6c33-5d2e-4b8a-a7c1-2e3f4a5b6c7d",
"flow_type": "kyb",
"flow_group_code": "Guardline KYB",
"case_envelope": {
"case_status": "escalated",
"decision_code": "pending_review",
"risk_level": "high",
"total_score": 720,
"priority": "P1",
"sla_deadline_at": "2026-07-18T17:00:00Z",
"completed_at": "2026-07-17T17:00:00Z"
},
"subject": {
"document": "12345678000199",
"document_type": "cnpj",
"name": "Acme Serviços Financeiros LTDA"
},
"representatives": [
{ "execution_id": "0c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f", "status": "completed", "name": "Maria Oliveira", "flag": false, "document": "47055107806", "document_type": "cpf" },
{ "execution_id": "1d2e3f4a-5b6c-7d8e-9f0a-1b2c3d4e5f6a", "status": "expired", "name": "João Pereira", "flag": true, "document": "61589720458", "document_type": "cpf" }
],
"rejection_reasons": [],
"derivation_reasons": [
{ "code": "provider_unavailable", "label_ptbr": "Consulta de QSA indisponível", "severity": "medium", "source": "kyb_provider" }
],
"edd_flagged": true
}

Reprovação terminal reconciliada no caso acima:

{
"event_type": "cmp.case.rejected",
"execution_id": "9a1f6c33-5d2e-4b8a-a7c1-2e3f4a5b6c7d",
"flow_type": "kyb",
"subject": { "document": "12345678000199", "document_type": "cnpj" },
"case_envelope": {
"case_status": "rejected",
"decision_code": "rejected",
"priority": "P1",
"completed_at": "2026-07-18T09:12:00Z"
},
"rejection_reasons": ["document_expired"]
}

Um motor de onboarding ou de decisão de terceiros que não implementa o envelope pode enviar sua análise completa de KYC de uma pessoa física. Três campos são obrigatórios; todo o restante é opcional e, quando presente, é indexado para que a mesa possa filtrar e exibir a informação. O corpo completo é preservado como o payload do caso. As chaves são aceitas em camelCase (como listadas) e, na maioria delas, também em snake_case.

CampoTipoDescrição
case_idstringIdentificador único da análise no sistema de origem. Chave de idempotência. external_id e id são aceitos como aliases
subject.personal.cpfstringCPF do cliente, 11 dígitos sem pontuação. Também é lido de subject.basicData.cpf, subject.cpf.cpf ou de um subject_document no nível raiz
decision.finalDecisionstringALLOW, REVIEW ou BLOCK, sem diferenciar maiúsculas e minúsculas. decision.final_decision é aceito
BlocoCampos lidos pela CMP
subject.personalname (também subject.basicData.name, subject.cpf.name, subject_name no nível raiz)
decisionfinalScore (0 a 100), thresholds.review, thresholds.block, workflowExplanation.{workflowId, workflowName, totalScore, reviewThreshold, blockThreshold, executionTimeMs, executedAt, stagesResults[]}
trustriskScore, riskLabel
facematchmatched, confidenceScore
livenessmode
facialriskScore, riskLevel
documentoscopiaqualityScore, confidenceScore, isExpired
complianceisPep, sanctions[], lawsuits[], govDebts[], mediaExposureUrls[]
contactmediaExposureUrls[]
deviceriskScore, isVpn, isEmulator, isRooted
financial.financialRiskrisk_level, financial_risk_score, is_on_collection
payload_versionRótulo da versão do contrato, v1 por padrão

A CMP deriva a prioridade e o nível de risco do caso a partir da decisão e dos sinais de compliance, biometria e dispositivo:

AtributoRegra
Prioridade (quanto menor, mais urgente)Valor base por decisão: BLOCK 1, REVIEW 3, ALLOW 5. Qualquer ocorrência em listas de sanções força 0. Um PEP eleva para no máximo 1. Processos judiciais, débitos com órgãos públicos, facial.riskLevel = high ou um dispositivo marcado como VPN, emulador ou com root elevam para no máximo 2
Nível de riscoBLOCK é critical. REVIEW é high quando o score final é pelo menos 90% do limiar de bloqueio, caso contrário medium. ALLOW é low. Sanções ou PEP elevam low e medium para high
Scoredecision.finalScore (ou workflowExplanation.totalScore), limitado a 0 a 100
{
"case_id": "kyc-2026-000451",
"subject": {
"personal": { "cpf": "11122233344", "name": "Roberto Alves Lima" }
},
"decision": {
"finalDecision": "REVIEW",
"finalScore": 65,
"thresholds": { "review": 50, "block": 80 },
"workflowExplanation": {
"workflowId": "wf-kyc-standard",
"workflowName": "kyc_standard",
"totalScore": 65,
"reviewThreshold": 50,
"blockThreshold": 80,
"executionTimeMs": 1830,
"executedAt": "2026-08-20T10:15:00Z"
}
},
"compliance": {
"isPep": true,
"sanctions": [],
"lawsuits": [{ "court": "TJSP", "number": "1001234-56.2024.8.26.0100", "type": "civil" }],
"govDebts": []
},
"facematch": { "matched": true, "confidenceScore": 88.5 },
"liveness": { "mode": "active" },
"facial": { "riskScore": 20, "riskLevel": "low" },
"documentoscopia": { "qualityScore": 92, "confidenceScore": 95, "isExpired": false },
"device": { "riskScore": 10, "isVpn": false, "isEmulator": false, "isRooted": false },
"financial": { "financialRisk": { "risk_level": "medium", "financial_risk_score": 55, "is_on_collection": false } }
}

Este payload chega à mesa Cadastro PF com prioridade 1 (PEP) e nível de risco high (o PEP eleva medium para high).

201 Created quando o caso é novo, 200 OK com created: false em um reenvio ou em uma reconciliação terminal:

{
"case_id": "9e1c8b3a-1234-5678-9abc-def012345678",
"external_id": "7b5c3d22-3e5f-4a7b-93b8-c6f5a2d4a4e2",
"created": true
}
StatusmessageCausa
400empty body, invalid jsonRequisição malformada
400execution_id e obrigatorioEnvelope sem execution_id
400flow_type "x" invalido (esperado kyc, kyb, kyc_minor ou kyc_representative)flow_type desconhecido
400subject e obrigatorio, case_envelope e obrigatorioObjetos do envelope ausentes
400subject.document e obrigatorioEvento terminal sem documento
400case_envelope.priority "x" invalida (esperado P0, P1, P2 ou P3)Prioridade fora do conjunto aceito
400case_id e obrigatorioPayload genérico sem identificador
400subject.personal.cpf e obrigatorioPayload genérico sem CPF
400decision.finalDecision deve ser ALLOW, REVIEW ou BLOCKPayload genérico com uma decisão inválida
401missing signature, invalid signature, stale timestamp e relacionadosCamada HMAC habilitada e a assinatura falhou
401missing api key, invalid api keyVeja Tokens de API
403token scope not authorized for this endpointO escopo do token não é ingest:kyc nem ingest
429ingest rate limit exceededLimite por token excedido

Os casos vivem em mesas (operações). Cada mesa tem uma fila de entrada, onde os casos novos chegam, e uma fila de supervisão para escalações. O código da mesa é o identificador estável usado pela API, por exemplo na requisição de transferência entre mesas; os nomes de exibição das filas são definidos no momento do deploy e podem ser renomeados por um administrador.

Código da mesaMesaTipo de casoEndpoint de ingestão
medMEDmed/api/v1/ingest/med
fraudeFraudefraude/api/v1/ingest/fraude
kycCadastro PFkyc/api/v1/ingest/kyc
kybCadastro PJkyb/api/v1/ingest/kyc
pldPLDpld/api/v1/ingest/pld
comercialComercialmantém o tipo da mesa de origemnenhum, recebe casos por transferência

Todo caso carrega um status genérico, compartilhado por todas as mesas, e um status de negócio que o refina:

Status genéricoSignificado
newCriado pela ingestão, aguardando distribuição ou que um analista o puxe
in_analysisAtribuído a um analista
escalatedEnviado para a fila de supervisão
decidedUma decisão foi registrada
closedEncerrado
failedA ocorrência não pôde ser aberta ou processada; o caso é liberado para reprocessamento

A mesa PLD acrescenta o seu próprio workflow sobre esse conjunto (novo, em_triagem, em_investigacao, aguardando_revisao_investigacao, aguardando_comite, pendente_geracao_xml, xml_gerado, comunicado_coaf, erro_siscoaf, retificado, cancelado, arquivado, entre outros). As suas transições são as publicadas aos receptores como webhooks de saída.

Os prazos de SLA são calculados na ingestão a partir da política de SLA da mesa e do status (configurável por mesa, fila e status, com um limiar de alerta antes do vencimento). A mesa Fraude também aceita um sla_deadline explícito no payload.

Um analista pode entregar um caso a outra mesa quando a análise revela uma natureza diferente (suspeita de fraude em um caso de onboarding, indícios de lavagem de dinheiro, necessidade de um parecer comercial). O caso mantém o seu tipo e o seu histórico, e retorna pelo mesmo caminho. Pares habilitados hoje:

DePara
Cadastro PF (kyc)Fraude, PLD, Comercial (e de volta)
Cadastro PJ (kyb)Fraude, PLD, Comercial (e de volta)

As transferências são registradas na trilha de auditoria com origem, destino, ator e justificativa. Elas não ficam visíveis ao sistema de origem pela API; a decisão que acaba encerrando o caso, sim.

A forma como o sistema de origem toma conhecimento da decisão do analista depende da mesa.

Para casos abertos pelo envelope de onboarding, a CMP envia a decisão do analista (aprovar, reprovar) de volta para a ONP da Guardline assim que ela é registrada, referenciando o execution_id. Apenas essas decisões terminais são propagadas: decisões intermediárias, como uma escalação ou uma solicitação de informações adicionais, permanecem na CMP e não geram evento na ONP. A ONP então retoma a execução e emite seus próprios eventos de onboarding para o integrador. Um integrador que usa ONP e CMP em conjunto consome, portanto, um único fluxo de webhooks, o descrito na referência da API da ONP, e não precisa fazer polling na CMP.

O retorno é entregue pelo mesmo outbox durável dos webhooks de saída descritos abaixo. Durante uma indisponibilidade temporária da ONP, ele é retentado um número pequeno de vezes ao longo de aproximadamente dois minutos e depois é marcado como esgotado; não há redrive automático depois disso, portanto recuperar a notificação exige um reenfileiramento manual pela operação da Guardline.

A mesa de PLD publica os marcos do seu workflow em receptores HTTP configurados para a instância. Um receptor é definido por um nome, uma URL de destino, um segredo HMAC e a lista de eventos que ele assina, e é provisionado pela Guardline durante a configuração da integração. Vários receptores podem assinar o mesmo evento.

EventoEmitido quandopld_status resultante
triagem_concluidaO alerta foi arquivado na triagem, após a investigação, ou pelo diretor ao arquivar um caso reprovado pelo comitê. Nesse terceiro caso a entrega carrega action: "pld_arquivar_reprovado" e chega logo após comite_reprovado, portanto convém rotear por payload.action e não apenas pelo nome do eventoarquivado_triagem ou arquivado
comite_aprovadoA sessão do comitê foi encerrada com aprovação da comunicaçãoaprovado_comite
comite_reprovadoA sessão do comitê foi encerrada reprovando a comunicaçãoreprovado_comite
coaf_registradoA comunicação ao COAF foi registrada (protocolo SISCOAF recebido)comunicado_coaf
coaf_erroO envio ao SISCOAF falhou e o erro foi registradoerro_siscoaf
coaf_retificadoA comunicação foi retificadaretificado
coaf_canceladoA comunicação foi canceladacancelado

Números de protocolo, hashes e recibos da comunicação ao COAF não são transportados no webhook, propositalmente. Eles ficam disponíveis para usuários autorizados na mesa.

Toda entrega envia o mesmo envelope; o bloco payload é estável entre os eventos de PLD, portanto um único decodificador atende a todos eles.

{
"event": "coaf_registrado",
"delivery_id": "3f0c9b1e-8d2a-4e6f-b5c7-1a2b3c4d5e6f",
"correlation_key": "PLD-2026-00042",
"case_id": "2ca0bd66-0ef9-44e6-9b47-6816264dd779",
"attempt": 1,
"timestamp": "2026-08-20T14:05:11Z",
"payload": {
"case_id": "2ca0bd66-0ef9-44e6-9b47-6816264dd779",
"numero_caso": "PLD-2026-00042",
"action": "pld_registrar_coaf",
"pld_status": "comunicado_coaf",
"occurred_at": "2026-08-20T14:05:10Z"
}
}
CampoDescrição
eventNome do evento da tabela acima
delivery_idIdentificador estável desta entrega, idêntico em todas as retentativas. Use-o para deduplicação
correlation_keyO número do caso de PLD
case_idUUID do caso
attempt1 para a primeira entrega, 2 e 3 para as retentativas
timestampQuando esta tentativa foi enviada
payload.actionA ação do workflow que produziu a transição (por exemplo pld_arquivar_triagem, pld_registrar_coaf, pld_retificar, comite_aprovado)
payload.pld_statusO status de PLD resultante
payload.motivoPresente apenas em coaf_retificado e coaf_cancelado: a justificativa informada pelo operador
payload.occurred_atQuando a transição foi efetivada
CabeçalhoDescrição
Content-TypeSempre application/json
X-Webhook-EventO nome do evento, para roteamento sem fazer o parsing do corpo
X-Webhook-DeliveryO identificador da entrega, mesmo valor de delivery_id no corpo
X-Webhook-SignatureHMAC-SHA256 do corpo bruto, em hexadecimal

A assinatura cobre apenas o corpo bruto da requisição (não há componente de timestamp, diferentemente da assinatura de entrada do onboarding).

  1. Leia os bytes do corpo bruto, antes de qualquer parsing de JSON.
  2. Calcule o HMAC-SHA256 do corpo com o segredo do receptor e codifique o resultado em hexadecimal.
  3. Compare com X-Webhook-Signature usando uma comparação em tempo constante.
import hmac, hashlib
def verify_cmp_webhook(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)

Uma entrega é bem-sucedida quando o receptor responde qualquer status 2xx em até 10 segundos. Caso contrário, a CMP faz novas tentativas:

TentativaEspera após a falha anterior
2Na próxima drenagem do outbox após a falha
3Pelo menos 30 segundos depois disso

O outbox é drenado por um job que roda a cada 60 segundos, portanto o intervalo de drenagem domina o tempo real e toda a janela de retentativas fica em torno de dois minutos. Após a terceira falha, a entrega é marcada como exhausted e não é mais reenviada automaticamente. As entregas são persistidas em um outbox antes da primeira tentativa, portanto um reinício da CMP nunca perde um evento; a garantia vale a partir do momento em que o registro da entrega é gravado. Reenfileirar uma entrega esgotada é uma operação manual executada pela operação da Guardline mediante solicitação, e não uma API de autoatendimento.

RequisitoDetalhe
ProtocoloHTTPS obrigatório
Versão do TLS1.2 ou superior
Resposta de sucessoQualquer código 2xx, corpo ignorado
TimeoutResponder em até 10 segundos
IdempotênciaDeduplicar por X-Webhook-Delivery (ou delivery_id)

Receba o webhook, persista-o ou enfileire-o e responda 200 imediatamente. Faça o processamento de forma assíncrona.

As decisões nas mesas de Fraude e MED são registradas na CMP com sua justificativa, código de decisão e efeitos operacionais (bloqueio cautelar, bloqueio preventivo de conta, inclusões em listas) e ficam visíveis no detalhe do caso e na trilha de auditoria do console. O pipeline de webhooks de saída é compartilhado por todas as mesas, mas nenhum evento é publicado para essas mesas no momento; quando a instituição precisa que o resultado de fraude ou MED seja enviado ao seu sistema core, a assinatura é habilitada como parte da configuração da integração.

Os tokens são gerenciados por administradores da CMP. Os endpoints abaixo exigem o cookie de sessão do console de um usuário com o papel admin, que é herdado pelo papel de diretor de PLD, de modo que um diretor de PLD também pode gerenciar tokens; eles não podem ser chamados com um token de API. As mesmas operações estão disponíveis no console.

GET /api/v1/api-tokens

Retorna todos os tokens com seu rótulo, prefixo, escopo, flag de atividade, limite de requisições, expiração, contador de uso e último uso. Os valores dos tokens nunca são retornados.

POST /api/v1/api-tokens
{
"label": "fpp-producao",
"scope": "ingest:fraude",
"rate_limit_max": 300,
"rate_limit_window_seconds": 60,
"expires_in_days": 365
}
CampoObrigatórioDescrição
labelsimNome de exibição
scopenãoUm dos escopos. Padrão: ingest
rate_limit_maxnãoRequisições por janela. Padrão: 60
rate_limit_window_secondsnãoDuração da janela. Padrão: 60
expires_in_daysnãoDias até a expiração. 0 ou ausente significa sem expiração

Resposta 201:

{
"ok": true,
"id": "c9a1e845-a565-43b6-ac29-2d3072b027b9",
"token": "cmp_e188905ec47a80ec035fe31a3264bf1a5f9231f1353ea24717cf311740305f11",
"token_prefix": "cmp_e188905e",
"label": "fpp-producao",
"scope": "ingest:fraude"
}

O campo token aparece apenas nesta resposta. Armazene-o imediatamente no cofre de segredos do sistema de origem; ele não pode ser recuperado depois. Se ele for perdido, crie um novo token e faça a rotação.

Rotação sem downtime: crie o novo token, configure-o no sistema de origem, confirme um ingest bem-sucedido e então desative o antigo.

PATCH /api/v1/api-tokens/{id}/toggle
{ "is_active": false }

A desativação mantém o registro do token e seu histórico de uso para auditoria. Um token desativado responde 401 invalid api key e pode ser reativado com is_active: true.

DELETE /api/v1/api-tokens/{id}

A exclusão é permanente.

GET /api/v1/settings/webhooks

Retorna o catálogo de todos os endpoints de entrada que a instância expõe (as quatro rotas de ingest mais os callbacks dos provedores de comunicação para WhatsApp, SMS e voz), com o caminho, os métodos aceitos, o tipo de autenticação e o cabeçalho, e o escopo de token exigido. O catálogo é derivado da tabela de rotas da versão em execução, portanto é a forma mais rápida de um administrador confirmar a URL exata a ser informada a um sistema de origem.

StatusSignificado
200Requisição processada; o caso já existia (replay idempotente, consolidação ou reconciliação)
201Caso criado
400Corpo malformado ou validação falhou. Corrija a requisição antes de tentar novamente
401Token de API ausente ou inválido, ou assinatura HMAC inválida
403O escopo do token não cobre o endpoint
404Um código referenciado não existe (por exemplo, um tipo_alerta de PLD desconhecido)
409Conflito com o estado atual do caso
429Limite de requisições excedido. Tente novamente após a janela
500Erro interno. Tente novamente com backoff e informe o request_id ao suporte
503Uma dependência está indisponível. Tente novamente com backoff
codeStatus típicoDescrição
BAD_REQUEST400Um campo falhou na validação; message indica qual
VALIDATION_ERROR400O corpo está vazio ou não é um JSON válido
UNAUTHORIZED401Problema de credencial
FORBIDDEN403Problema de escopo
NOT_FOUND404Código de referência desconhecido
CONFLICT409Conflito de estado
DUPLICATE_EXTERNAL_ID409O identificador de ingestão já havia sido usado nessa mesa
ALREADY_EXISTS409A mesa PLD já possui um alerta com esse alerta_externo_id
RATE_LIMITED429Limite de requisições excedido
SERVICE_UNAVAILABLE503Dependência indisponível
INTERNAL_ERROR500Falha inesperada

Tratamento recomendado: trate 400, 401, 403 e 404 como permanentes para aquela requisição (alerte o operador, não faça novas tentativas cegamente); trate 429, 500 e 503 como transitórios (faça novas tentativas com backoff exponencial, as chaves de idempotência tornam as retentativas seguras).

MétodoCaminhoAutenticaçãoDescrição
POST/api/v1/ingest/fraudeToken de API (ingest:fraude)Abre um caso na mesa de Fraude
POST/api/v1/ingest/medToken de API (ingest:med)Abre um caso na mesa de MED
POST/api/v1/ingest/pldToken de API (ingest:pld)Abre ou consolida um caso na mesa de PLD
POST/api/v1/ingest/kycToken de API (ingest:kyc) + HMAC opcionalAbre ou reconcilia um caso na mesa Cadastro PF ou Cadastro PJ
GET/api/v1/api-tokensSessão de administradorLista os tokens de API
POST/api/v1/api-tokensSessão de administradorCria um token de API
PATCH/api/v1/api-tokens/{id}/toggleSessão de administradorAtiva ou desativa um token
DELETE/api/v1/api-tokens/{id}Sessão de administradorExclui um token
GET/api/v1/settings/webhooksSessão de administradorCatálogo dos endpoints de entrada
GET/healthz, /readyz, /livezNenhumaProbes de liveness e readiness

Versão 18, atualizada em