Skip to content

CMP API Reference

This document describes how to integrate with the Guardline Case Management Platform (CMP) API. It covers API tokens, opening cases on each analysis desk (fraud alerts, MED requests, AML alerts and onboarding cases), idempotency and rate limiting, how analyst decisions flow back to the originating system, outbound webhooks, and error handling.

The integration model follows a clear separation of responsibilities: the integrator’s engine detects and opens the case, Guardline queues, distributes, analyzes and decides. Any decision engine, internal or third party, can open cases programmatically. The CMP then applies queues, SLAs, distribution, approval chains, committee sessions and the audit trail exactly as it does for cases generated by the other modules of the Guardline Suite.

The integration involves four participants:

ParticipantResponsibility
Source systemDetects an event (transaction alert, MED request, AML alert, onboarding derivation) and opens a case through the ingest API
Guardline CMP APIValidates, deduplicates, routes the case to a desk and queue, computes SLA and distributes it to an analyst
Guardline CMP consoleWeb console where analysts, supervisors and administrators work the cases and manage tokens
Receiver (optional)Integrator endpoint that receives outbound webhooks for AML workflow events

Each desk has its own ingest endpoint. All of them are POST, accept application/json and authenticate with an API token scoped to that desk.

DeskEndpointToken scopeCase identifier
Fraud (Fraude)/api/v1/ingest/fraudeingest:fraudeexternal_id
MED (special refund mechanism)/api/v1/ingest/medingest:medid, event_id, notification_id or med_id
AML (anti money laundering)/api/v1/ingest/pldingest:pldalerta_externo_id
Onboarding, individuals (KYC) and companies (KYB)/api/v1/ingest/kycingest:kycexecution_id (onboarding envelope) or case_id (generic payload)

Every other route of the CMP API (/api/v1/cases, /api/v1/queues, /api/v1/users and so on) belongs to the console and is authenticated by the analyst’s session cookie. Those routes are not part of the integration contract and are not documented here, except for the token administration endpoints in Token Administration.

All API calls follow the REST pattern over HTTPS with JSON payloads.

EnvironmentBase URL
Sandboxhttps://{instance}.cmp.dev.guardline.com.br
Productionhttps://{instance}.cmp.prod.guardline.com.br

The {instance} value is provisioned during integrator setup and identifies the dedicated infrastructure. Each instance has its own isolated database and application. A token issued on one instance authenticates only against that instance.

HTTP requests are rejected. HTTPS with TLS 1.2 or higher is required in all environments.

Every ingest call requires the X-API-Key header carrying an API token.

X-API-Key: cmp_e188905ec47a80ec035fe31a3264bf1a5f9231f1353ea24717cf311740305f11

Tokens have the shape cmp_ followed by 64 hexadecimal characters. They are created by a CMP administrator, either in the console (API tokens screen) or through the token administration endpoints. The plaintext value is displayed only once, in the creation response. Internally the CMP stores the SHA-256 hash of the token together with a display prefix (the first 12 characters, such as cmp_e188905e) so administrators can recognize a token without exposing it.

Each token carries:

AttributeDescription
labelFree text name, for example fpp-producao or onp-webhook-kyc
scopeThe desk the token may write to. See Scopes
rate_limit_max, rate_limit_window_secondsPer token rate limit. Defaults to 60 requests per 60 seconds
expires_in_daysOptional expiry. 0 (the default) means the token never expires

A credential problem always answers 401 or 403, never 400:

StatusMessageCause
401missing api keyThe X-API-Key header was not sent or is empty
401invalid api keyThe token is unknown, was deactivated, was deleted or has expired
403token scope not authorized for this endpointThe token exists but its scope does not cover the endpoint

A 400 means the token was accepted and the request body was rejected, so reissuing the token will not resolve it.

Every rejected call (missing key, invalid key, wrong scope, rate limit) is recorded in the CMP audit trail with the source IP, path and reason. Successful ingests are recorded too, with the full body.

ScopeEndpoints allowed
ingest:fraudePOST /api/v1/ingest/fraude
ingest:medPOST /api/v1/ingest/med
ingest:pldPOST /api/v1/ingest/pld
ingest:kycPOST /api/v1/ingest/kyc (KYC and KYB cases share this endpoint and scope)
ingestAll four ingest endpoints

Use the narrowest scope that covers the source system. The generic ingest scope exists for tooling and should not be issued to a production engine that writes to a single desk. A token created without an explicit scope receives the generic ingest scope, which is accepted on all four desk endpoints. Scope strings are not validated at creation, so a typo produces a token that is rejected on every endpoint.

Rate limiting is applied per token, per desk endpoint and per API replica, in a fixed window. The limit and the window are attributes of the token (rate_limit_max and rate_limit_window_seconds, defaults of 60 requests per 60 seconds) and are chosen by the administrator at creation time. Each ingest route counts its own window and each replica keeps its own counters in memory, so the effective ceiling is higher than the configured number when several replicas serve traffic. Windows above 120 seconds are not reliable: a window is discarded two minutes after its last use, regardless of rate_limit_window_seconds. Size the limit for the peak of the source system, keeping in mind that retries with backoff on the sender side can produce bursts.

When the limit is exceeded the API answers 429 with the message ingest rate limit exceeded. Wait for the window to elapse and retry; the request was not processed.

The request body is limited to 1 MB by default, and the limit is configurable per instance. A body above the limit is rejected with 413. Decide retries from the HTTP status rather than from the code field: an oversized body currently reports code: INTERNAL_ERROR alongside the 413.

The optional X-Tenant-Slug header identifies the tenant of the source system and is recorded in the audit trail only on rejected calls, not on a successful ingest. When omitted it defaults to default. It does not change routing: the instance is the isolation boundary.

Ingest endpoints return the resource body directly, without an envelope. The shape is endpoint specific and documented in each section; the three generic desks (fraud, MED, onboarding) share this one:

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

Errors use a single envelope on every endpoint:

{
"error": true,
"message": "external_id é obrigatório",
"code": "BAD_REQUEST",
"request_id": "5c1e8f2a-7b3d-4c9e-a1f0-2d6b8e4a9c7f"
}
FieldDescription
errorAlways true on an error response
messageHuman readable reason. Validation messages are in Portuguese or English depending on the desk
codeStable machine readable code. See Error Codes
request_idCorrelation identifier, also returned in the X-Request-ID response header. Quote it when contacting support

Outside production the envelope also carries a details field with the raw internal error. In production the field is omitted.

Every ingest endpoint is idempotent on a natural key chosen by the source system, scoped to the desk:

DeskNatural key
Fraudexternal_id
MEDid, event_id, notification_id or med_id (first present), otherwise the SHA-256 of the raw body, stored and returned as sha256: followed by the hash
AMLalerta_externo_id
Onboardingexecution_id (onboarding envelope) or case_id (generic KYC payload)

The first call for a key creates the case and answers 201. Any later call with the same key answers 200 with created: false (or is_new_case: false on the AML desk) and the identifier of the existing case. Nothing is overwritten: the case is immutable after creation and the analyst’s work is never replaced by a resend. This makes the endpoints safe to retry after a network timeout without generating duplicate work for the desk.

The idempotency window is unbounded: the key stays unique for the lifetime of the desk.

POST /api/v1/ingest/fraude

Scope: ingest:fraude. Opens a case on the Fraud desk from a transaction alert produced by a fraud detection engine (the Guardline FPP or a third party engine).

The body is a JSON object. Only three fields are mandatory; everything else enriches the case. Alternative key names accepted for the same field are listed in the alias column. The complete body is preserved as the case payload, so keys that are not listed here are kept and visible to the analyst even though they are not indexed.

FieldTypeRequiredAliasesDescription
external_idstringyesid, event_idUnique identifier of the alert in the source system. Idempotency key
subject_documentstringyesdocumentoCPF or CNPJ of the investigated customer. Unlike the AML desk, the format is not validated: punctuation is not stripped and the digit count is not checked, so the value is stored exactly as sent and should be normalized by the caller
transaction_amountnumberyesamount, valorAmount in BRL, must be greater than zero. Stored in cents
subject_namestringnocliente_nome, nomeCustomer name
counterparty_namestringnocontraparte_nomeName of the counterparty (beneficiary)
transaction_typestringnotipo_transacaoTransaction type, lowercased. Defaults to pix
risk_levelstringnoriscoOnly low, medium, high and critical are recognized. Derived from score when absent or empty; any other value leaves the case without a risk level
scoreintegernoEngine score on a 0 to 1000 scale. See Score, Risk and Priority
priorityintegerno0 to 9, lower is more urgent. Defaults to 3. Values outside the range are clamped
sla_deadlinestring (RFC 3339)noExplicit SLA deadline. When absent, the deadline comes from the SLA policy configured for the desk, and the case is created without a deadline when no policy applies. A value that cannot be parsed is silently ignored and the desk policy applies instead; no 400 is returned
fraud_analysisobjectnoFull decision explanation and customer context. See The fraud_analysis Block

The Fraud desk expects the engine score on the FPP scale (0 to 1000). The CMP stores score / 10, capped at 100, on the case so that queues and dashboards share one scale across desks. The division is an integer division, so the result is truncated and not rounded: 999 is stored as 99. The original value stays in the case payload.

When risk_level is absent or empty, it is derived from the raw score:

Score (0 to 1000)Derived risk_level
950 or morecritical
850 to 949high
700 to 849medium
below 700low

When neither risk_level nor score is sent, the case is created with risk_level = medium.

Derivation runs only when the field is absent or empty. Only the four values above are recognized, and an unrecognized non empty value skips the derivation and leaves the case with no risk level at all, so send one of the four values or omit the field entirely.

priority orders the case in the queue and feeds the distribution engine together with the score. It is independent from the risk level.

fraud_analysis is what the analyst’s fraud analysis panel renders. It is stored verbatim and supplies the workflow explanation (stages, policies, rules and their contributions), the transaction detail with device and location, the customer profile with behavioral baselines and recent transactions, anomaly comparisons, and the customer and counterparty timelines. Send it on every alert so the panel reflects this case.

{
"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": [] }
}

All sub-blocks are optional. Send whatever the engine has: a sub-block that is not sent is simply not rendered, while a sub-block whose field types do not match the schema is discarded, so match the documented shape.

Minimal alert:

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
}'

Complete alert:

{
"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, new case:

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

200 OK, the external_id already exists on the Fraud desk:

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

The new case enters the Fraud desk with status new, business status aguardando_analise and a queued work item. The distribution engine assigns it to an available analyst of the entry queue.

StatusmessageCause
400empty bodyNo body was sent
400invalid jsonThe body is not valid JSON
400external_id é obrigatórioMissing identifier
400subject_document é obrigatórioMissing customer document
400transaction_amount deve ser maior que zeroMissing, non numeric or non positive amount
401missing api key, invalid api keySee API Tokens
403token scope not authorized for this endpointToken scope is not ingest:fraude or ingest
429ingest rate limit exceededPer token limit exceeded
POST /api/v1/ingest/med

Scope: ingest:med. Opens a case on the MED desk from a special refund mechanism request (Mecanismo Especial de Devolução) received by the institution.

The MED desk was the first desk of the platform and accepts the widest set of key aliases so that existing PIX back office exports can be forwarded with minimal transformation. The complete body is preserved as the case payload.

FieldTypeRequiredAliasesDescription
valor_solicitadonumberyesamount, valorAmount requested for refund, in BRL, greater than zero. Stored in cents
idstring or numberrecommendedevent_id, notification_id, med_idIdentifier of the MED request in the source system. Idempotency key. When all are absent the SHA-256 of the raw body is used, stored and returned as sha256: followed by the hash, so a byte identical resend is still deduplicated. The body hash does not survive any change in serialization (key order, number formatting, a timestamp carried in the payload), so it does not replace sending a real identifier
request_idstringnomed_request_id, idMED protocol number shown to the analyst. When absent it falls back to a value derived from a re-serialized copy of the payload, which is not guaranteed to match the external_id returned to the caller, so send it explicitly
requested_atstring (RFC 3339)nocreated_at, event_atWhen the request was opened. Defaults to the ingest time
motivostringnoreason_code, reason, tipogolpe (default), fraude or erro_operacional. Unknown values fall back to golpe
statusstringnomed_statusaberta (default), em_analise, aguardando_instituicao, aprovado, negado or recusado. Unknown values fall back to aberta
prazo_limite_atstring (RFC 3339)nodeadline_atRegulatory response deadline of the MED request
recebedoraobjectnorecipient, counterpartyReceiving institution: { "nome": "...", "ispb": "..." }. Under recebedora only nome is read; name works under recipient and counterparty. Flat recebedora_nome, counterparty_name and recebedora_ispb keys are accepted too. When no receiving institution name can be resolved the case is stored with a placeholder name
recebedora_respondeubooleannoWhether the receiving institution has already answered
valor_devolvidonumbernoAmount already refunded, in BRL
data_devolucao_atstring (RFC 3339)noWhen the refund happened
subject_namestringnocliente_nome, nomeCustomer name
subject_documentstringnocliente_documento, documentoCustomer CPF or CNPJ
transaction_typestringnotipo_transacaoDefaults to pix
risk_levelstringnorisklow, medium, high or critical. Unknown values are ignored
scoreintegerno0 to 100. Unlike the Fraud desk, the MED score is not normalized: it must already be on the 0 to 100 scale, and values outside that range are rejected
priorityintegerno0 to 9, lower is more urgent. Defaults to 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 when the case is new, 200 OK with created: false when the identifier already exists on the MED desk:

{
"case_id": "8d1b3f4e-2a6c-4d7e-9b0a-1c2d3e4f5a6b",
"external_id": "MED-2026-000123",
"created": true
}
StatusmessageCause
400empty body, invalid jsonMalformed request
400missing or invalid valor_solicitadoAmount absent, non numeric or not greater than zero
401missing api key, invalid api keySee API Tokens
403token scope not authorized for this endpointToken scope is not ingest:med or ingest
429ingest rate limit exceededPer token limit exceeded
POST /api/v1/ingest/pld

Scope: ingest:pld. Opens or enriches a case on the AML desk (prevenção à lavagem de dinheiro) from a transactional alert produced by a monitoring engine. The AML desk differs from the others in two ways: alerts for a customer who already has an open case are consolidated into that case instead of opening a new one, and cash movements at or above the regulatory threshold are flagged as an automatic COE (comunicação de operação em espécie) that skips triage.

FieldTypeRequiredAliasesDescription
alerta_externo_idstringyesUnique identifier of the alert in the source system. Idempotency key. Limited to 100 characters; a longer value currently fails as a server error instead of a validation error, so keep within the limit
cpf_cnpjstringyesCPF (11 digits) or CNPJ (14 digits) of the investigated customer. Punctuation is stripped before validation
tipo_alertastringyesAlert type code, case insensitive. See Alert Types
subject_namestringrecommendedcliente_nome, nomeCustomer name
score_risconumberrecommendedscoreRisk score. Both 0 to 100 and 0 to 1000 scales are accepted; values above 100 are divided by 10
valor_totalnumberrecommendedvalorTotal amount of the movement, in BRL. Used by the COE rule
valor_total_centavosintegernovalor_centavosSame amount in cents. Takes precedence over valor_total when both are present
tipologia_sugeridastring[]noTypology codes suggested by the engine, for example ["PIX001", "EST001"]
dados_clienteobjectnoFree form customer context (declared income, activity, city, state). Stored verbatim and shown in the dossier
dados_transacionaisobjectnoFree form transactional context (number of operations, period, channels). Stored verbatim
contrapartesarraynoCounterparties involved. Stored verbatim
is_coebooleannoForces the automatic COE classification regardless of type and amount
priorityintegerno0 to 9, lower is more urgent. Defaults to 3. An automatic COE always lands at priority 1
fpp_source_urlstringnoDeep link back to the alert in the source system, shown in the dossier

tipo_alerta must be one of the codes below. An unknown code is rejected with 404.

CodeDescription
pixPIX transfer
tedTED transfer
docDOC transfer
boletoBoleto payment
especieCash movement (notes). The only type eligible for the automatic COE rule
cambioForeign exchange operation
cartaoCard operation
depositoDeposit
saqueWithdrawal
transferenciaGeneric transfer between accounts
outroAny other movement

Each alert goes through four steps in a single transaction:

  1. Idempotency. If an alert with the same alerta_externo_id already exists, the API answers 200 with is_new_case: false and consolidated_into set to the case number that holds the original alert. No case or alert data is written; the resend is recorded in the audit trail. Two calls carrying the same identifier that arrive at the same instant are a different situation: one of them loses the race on the unique index and gets 409 with code ALREADY_EXISTS, which is safe to treat as a duplicate.
  2. COE detection. The alert is an automatic COE when is_coe is true, or when tipo_alerta is especie and the total amount is at or above R$ 50.000,00. An automatic COE always creates a new case (it is never consolidated), starts at AML status pendente_geracao_xml with priority 1, and is projected as decided / aprovado on the generic case status so it shows up as ready for the COAF communication step.
  3. Consolidation. When the alert is not a COE and the same cpf_cnpj already has an active AML case (any AML status other than arquivado_triagem, arquivado, comunicado_coaf, retificado or cancelado), the alert is attached to that case. The API answers 200 with is_new_case: false and consolidated_into set to the existing case number. The analyst sees the new alert in the dossier of the case they are already working. A COE alert always opens its own case and is never consolidated into an existing active case. COE also requires the source system to mark the alert as a cash operation (tipo_alerta of especie, or the explicit is_coe flag): the amount threshold alone does not trigger it.
  4. New case. Otherwise a new AML case is created with status new, business status aguardando_analise, AML status novo, a 45 day selection deadline (prazo_selecao) and a human readable case number in the form PLD-YYYY-NNNNN. The API answers 201.

Minimal alert:

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

Recommended alert:

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"
}'

Cash movement that triggers an automatic COE:

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

201 Created, new case:

{
"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, duplicate alert or alert consolidated into an active case of the same customer:

{
"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"
}
FieldDescription
case_idUUID of the case that holds the alert
case_pld_detail_idUUID of the AML detail record of that case
numero_casoHuman readable case number, the identifier operators quote
is_new_casetrue when a case was created by this call
is_coe_automaticatrue when the case is an automatic COE. Populated only when this call creates or consolidates the case: a plain idempotent replay returns false even for a COE case, so read it from the creation response and not from a replay
consolidated_intoPresent only when is_new_case is false: the case number that absorbed the alert, either because the alerta_externo_id was already known or because the customer had an active case
alerta_externo_idEcho of the request identifier

To distinguish the two 200 situations compare numero_caso with what the source system expected: a duplicate returns the case of the original alert, a consolidation returns a case that was opened by a different alert.

StatusmessageCause
400empty body, invalid jsonMalformed request
400alerta_externo_id is requiredMissing identifier
400cpf_cnpj must be a valid 11 or 14-digit documentAfter removing non digits the document is not 11 or 14 characters long
400tipo_alerta is requiredMissing alert type
404pld_alert_type "xyz" not foundtipo_alerta is not one of the alert types; the message quotes the value that was sent
401missing api key, invalid api keySee API Tokens
403token scope not authorized for this endpointToken scope is not ingest:pld or ingest
429ingest rate limit exceededPer token limit exceeded
POST /api/v1/ingest/kyc

Scope: ingest:kyc. Opens a case on the onboarding desks: Cadastro PF (KYC, individuals) or Cadastro PJ (KYB, companies). There is no separate /ingest/kyb route; the desk is chosen by the flow_type of the payload.

The endpoint accepts two body shapes, discriminated by the event_type field:

ShapeWhenDiscriminator
Onboarding envelopeThe case comes from the Guardline ONP, or from an onboarding engine that follows the same contract. Supports KYC, KYC minor, legal representative and KYB flows, and carries terminal decisions back for reconciliationevent_type is cmp.case.review, cmp.case.approved or cmp.case.rejected
Generic KYC payloadA third party decision engine sends its full KYC analysis for an individualevent_type absent or any other value

Both shapes answer with the same { case_id, external_id, created } body.

Besides the API token, the endpoint can require an HMAC signature. The signature layer is enabled per instance, when a shared secret is provisioned during integration setup; until then only X-API-Key is enforced. When enabled, the signature is verified before the API token.

HeaderValue
X-Guardline-TimestampUnix time in seconds (integer) at the moment of signing
X-Guardline-SignatureLowercase hexadecimal HMAC-SHA256 of {timestamp}.{body}

Signing procedure:

  1. Serialize the body once. The exact bytes sent must be the bytes signed; do not re-serialize or pretty print after signing.
  2. Concatenate the timestamp, a literal dot and the raw body: {timestamp}.{body}.
  3. Compute HMAC-SHA256 of that string with the shared secret and encode the digest in 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"

The timestamp must be within 5 minutes of the server clock (the tolerance is configurable per instance). Signature failures answer 401 with one of missing signature, missing timestamp, malformed timestamp, stale timestamp, malformed signature or invalid signature.

This is the same format the Guardline ONP uses for its outgoing webhooks, so an integrator that already verifies ONP webhooks can reuse the routine to sign calls to the CMP.

The envelope is the body the Guardline ONP posts to the CMP when an onboarding execution is derived to manual analysis, and again when the execution reaches a terminal decision. The ONP API reference describes the producer side; this section describes what the CMP expects and does.

event_typeEffect
cmp.case.reviewCreates the case and queues it on the desk. This is the only event that creates a case. A resend for the same execution_id answers 200 with created: false
cmp.case.approvedReconciles a terminal approval onto a case previously created by a review. If the case has no decision yet, the approval is recorded as the decision. Never creates a case
cmp.case.rejectedSame as above for a rejection. The kyc_reject_* (or kyb_reject_*) decision code is chosen from rejection_reasons

A terminal event for an execution_id that never produced a review answers 200 with an empty case_id and created: false: the execution was auto decided by the engine, never reached the desk, and the CMP deliberately does not fabricate a queued case for it. A terminal event never overwrites a decision an analyst already recorded.

FieldTypeRequiredDescription
event_typestringyesSee Event Semantics
execution_idstringyesIdentifier of the onboarding execution. Stored as the case external_id and used as the idempotency key
flow_typestringyeskyc (adult individual), kyc_minor (minor with a legal representative), kyc_representative (the representative’s own execution, reviewed as its own case) or kyb (company). kyb routes to the Cadastro PJ desk, the others to Cadastro PF
subjectobjectyesSee below
case_envelopeobjectyesSee below
event_idstringnoProducer side event identifier, stored with the case
fired_atstring (RFC 3339)noWhen the producer emitted the event
tenant_idstringnoProducer tenant, informational
flow_id, flow_group_codestringnoFlow and flow group of the execution, informational
edd_flaggedbooleannoThe execution requires enhanced due diligence. Shown to the analyst
rejection_reasonsstring[]noFree form reasons behind a rejection. Used to classify the rejection decision code
derivation_reasonsobject[]noWhy the engine derived the case to manual analysis: { "code", "label_ptbr", "severity", "source", "detail" }. Rendered verbatim in the dossier
representativeobjectnokyc_minor only: { "execution_id", "status" } of the legal representative’s execution
guardian_typestringnokyc_minor only: parent, mother, father or other
representativesobject[]nokyb only: the company’s legal representatives, { "execution_id", "status", "name", "flag", "document", "document_type" }. flag is true when the representative was rejected or expired. Entries without both execution_id and name are dropped

subject:

FieldTypeRequiredDescription
documentstringterminal events onlyCPF or CNPJ, digits only (punctuation is stripped). A cmp.case.review may arrive with an empty document when the execution was derived before the identity step completed; the analyst resolves the identity on the desk
document_typestringnocpf or cnpj
namestringnoSubject name, shown in the queue
email, phone, birth_datestringnoCaptured in the case payload

case_envelope:

FieldTypeRequiredDescription
prioritystringyesP0, P1, P2 or P3, lower is more urgent. Mapped to the case priority 0 to 3. Any other value is rejected
case_statusstringnoEngine status: approved, rejected, blocked, escalated or other. Drives the workflow decision shown to the analyst (see mapping below)
decision_codestringnoEngine decision: approved, rejected or pending_review (the short forms approve, reject and review are also accepted). Drives the terminal CMP decision on cmp.case.approved / cmp.case.rejected
risk_levelstringnolow, medium, high or critical, case insensitive. Unknown values are ignored
total_scorenumbernoEngine score. Stored as the workflow score and, clamped to 0 to 100, as the case score used by queues
sla_deadline_at, completed_at, expires_atstring (RFC 3339)noProducer timestamps. completed_at becomes the decision time on a terminal event
SourceCase attributeRule
case_envelope.case_statusWorkflow decision shown on the deskapproved becomes ALLOW; rejected and blocked become BLOCK; anything else becomes REVIEW
case_envelope.decision_code + rejection_reasonsTerminal decision codeapproved records kyc_approve_onboarding (kyb_approve_onboarding for companies). rejected records kyc_reject_fraud_suspicion when the reasons mention fraud, suspicious or scam; kyc_reject_document_invalid when they mention document, invalid_doc, expired or illegible; kyc_reject_compliance otherwise. pending_review records nothing: the analyst decides
case_envelope.priorityCase priorityP0 to P3 map to 0 to 3
case_envelope.risk_levelCase risk levelLowercased; unknown values leave the risk level unset
case_envelope.total_scoreCase scoreRounded and clamped to 0 to 100
subject.name, subject.documentQueue columnsShown in the desk listing

Cases created by a cmp.case.review enter the desk with status new, business status aguardando_analise and a queued work item, exactly like the other desks. Only the envelope is persisted at ingest time; the full dossier (documents, biometrics, provider results, decision tree) is fetched from the ONP on demand when the analyst opens the case.

KYC case derived to manual analysis:

{
"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"
}

KYB case derived to manual analysis:

{
"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
}

Terminal rejection reconciled onto the case above:

{
"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"]
}

A third party onboarding or decision engine that does not implement the envelope can send its full KYC analysis of an individual. Three fields are mandatory; everything else is optional and, when present, is indexed so the desk can filter and display it. The complete body is preserved as the case payload. Keys are accepted in camelCase (as listed) and, for most of them, in snake_case.

FieldTypeDescription
case_idstringUnique identifier of the analysis in the source system. Idempotency key. external_id and id are accepted as aliases
subject.personal.cpfstringCPF of the customer, 11 digits without punctuation. Also read from subject.basicData.cpf, subject.cpf.cpf or a top level subject_document
decision.finalDecisionstringALLOW, REVIEW or BLOCK, case insensitive. decision.final_decision is accepted
BlockFields read by the CMP
subject.personalname (also subject.basicData.name, subject.cpf.name, top level subject_name)
decisionfinalScore (0 to 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_versionContract version label, defaults to v1

The CMP derives the case priority and risk level from the decision and the compliance, biometric and device signals:

AttributeRule
Priority (lower is more urgent)Base value by decision: BLOCK 1, REVIEW 3, ALLOW 5. Any sanctions hit forces 0. A PEP raises to at most 1. Lawsuits, government debts, facial.riskLevel = high, or a device flagged as VPN, emulator or rooted raise to at most 2
Risk levelBLOCK is critical. REVIEW is high when the final score is at least 90% of the block threshold, otherwise medium. ALLOW is low. Sanctions or PEP raise low and medium to high
Scoredecision.finalScore (or workflowExplanation.totalScore), clamped to 0 to 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 } }
}

This payload lands on the Cadastro PF desk with priority 1 (PEP) and risk level high (PEP raises medium to high).

201 Created when the case is new, 200 OK with created: false on a resend or on a terminal reconciliation:

{
"case_id": "9e1c8b3a-1234-5678-9abc-def012345678",
"external_id": "7b5c3d22-3e5f-4a7b-93b8-c6f5a2d4a4e2",
"created": true
}
StatusmessageCause
400empty body, invalid jsonMalformed request
400execution_id e obrigatorioEnvelope without execution_id
400flow_type "x" invalido (esperado kyc, kyb, kyc_minor ou kyc_representative)Unknown flow_type
400subject e obrigatorio, case_envelope e obrigatorioMissing envelope objects
400subject.document e obrigatorioTerminal event without a document
400case_envelope.priority "x" invalida (esperado P0, P1, P2 ou P3)Priority outside the accepted set
400case_id e obrigatorioGeneric payload without identifier
400subject.personal.cpf e obrigatorioGeneric payload without CPF
400decision.finalDecision deve ser ALLOW, REVIEW ou BLOCKGeneric payload with an invalid decision
401missing signature, invalid signature, stale timestamp and relatedHMAC layer enabled and the signature failed
401missing api key, invalid api keySee API Tokens
403token scope not authorized for this endpointToken scope is not ingest:kyc or ingest
429ingest rate limit exceededPer token limit exceeded

Cases live on desks (operations). Each desk has an entry queue where new cases land and a supervisor queue for escalations. The desk code is the stable identifier used by the API, for example in the cross-desk transfer request; queue display names are chosen at deployment time and can be renamed by an administrator.

Desk codeDeskCase typeIngest endpoint
medMEDmed/api/v1/ingest/med
fraudeFraudefraude/api/v1/ingest/fraude
kycCadastro PFkyc/api/v1/ingest/kyc
kybCadastro PJkyb/api/v1/ingest/kyc
pldAMLpld/api/v1/ingest/pld
comercialComercialkeeps the type of the originating desknone, receives cases by transfer

Every case carries a generic status, shared by all desks, and a business status that refines it:

Generic statusMeaning
newCreated by ingest, waiting for distribution or pull
in_analysisAssigned to an analyst
escalatedSent to the supervisor queue
decidedA decision was recorded
closedClosed
failedThe occurrence could not be opened or processed; the case is released for reprocessing

The AML desk adds its own workflow on top (novo, em_triagem, em_investigacao, aguardando_revisao_investigacao, aguardando_comite, pendente_geracao_xml, xml_gerado, comunicado_coaf, erro_siscoaf, retificado, cancelado, arquivado, among others). Its transitions are the ones published to receivers as outbound webhooks.

SLA deadlines are computed at ingest from the SLA policy of the desk and status (configurable per desk, queue and status, with a warning threshold before expiry). The Fraud desk also accepts an explicit sla_deadline in the payload.

An analyst can hand a case to another desk when the analysis reveals a different nature (fraud suspicion on an onboarding case, money laundering indicators, need for a commercial opinion). The case keeps its type and its history, and returns the same way. Pairs enabled today:

FromTo
Cadastro PF (kyc)Fraude, AML, Comercial (and back)
Cadastro PJ (kyb)Fraude, AML, Comercial (and back)

Transfers are recorded in the audit trail with origin, destination, actor and justification. They are not visible to the source system through the API; the decision that eventually closes the case is.

How the source system learns about the analyst’s decision depends on the desk.

For cases opened through the onboarding envelope, the CMP pushes the analyst’s decision (approve, reject) back to the Guardline ONP as soon as it is recorded, referencing the execution_id. Only these terminal decisions propagate: intermediate decisions such as an escalation or a request for additional information stay in the CMP and produce no ONP event. The ONP then resumes the execution and emits its own onboarding events to the integrator. An integrator that uses ONP and CMP together therefore consumes a single webhook stream, the one described in the ONP API reference, and does not need to poll the CMP.

The pushback is delivered through the same durable outbox as the outbound webhooks below. During a temporary ONP outage it is retried a small number of times over roughly two minutes and is then marked exhausted; there is no automatic redrive after that, so recovering the notification requires a manual requeue by Guardline operations.

The AML desk publishes its workflow milestones to HTTP receivers configured for the instance. A receiver is defined by a name, a target URL, an HMAC secret and the list of events it subscribes to, and is provisioned by Guardline during integration setup. Several receivers can subscribe to the same event.

EventEmitted whenResulting pld_status
triagem_concluidaThe alert was archived during triage, after investigation, or by the director when archiving a case the committee rejected. In that third case the delivery carries action: "pld_arquivar_reprovado" and arrives right after comite_reprovado, so route on payload.action and not on the event name alonearquivado_triagem or arquivado
comite_aprovadoThe committee session closed with approval of the communicationaprovado_comite
comite_reprovadoThe committee session closed rejecting the communicationreprovado_comite
coaf_registradoThe COAF communication was registered (SISCOAF protocol received)comunicado_coaf
coaf_erroThe SISCOAF submission failed and the error was recordederro_siscoaf
coaf_retificadoThe communication was rectifiedretificado
coaf_canceladoThe communication was cancelledcancelado

Protocol numbers, hashes and receipts of the COAF communication are deliberately not carried in the webhook. They are available to authorized users on the desk.

Every delivery posts the same envelope; the payload block is stable across the AML events so a single decoder handles all of them.

{
"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"
}
}
FieldDescription
eventEvent name from the table above
delivery_idStable identifier of this delivery, identical across retries. Use it for deduplication
correlation_keyThe AML case number
case_idUUID of the case
attempt1 for the first delivery, 2 and 3 for the retries
timestampWhen this attempt was sent
payload.actionThe workflow action that produced the transition (for example pld_arquivar_triagem, pld_registrar_coaf, pld_retificar, comite_aprovado)
payload.pld_statusThe resulting AML status
payload.motivoPresent only on coaf_retificado and coaf_cancelado: the justification entered by the operator
payload.occurred_atWhen the transition was committed
HeaderDescription
Content-TypeAlways application/json
X-Webhook-EventThe event name, for routing without parsing the body
X-Webhook-DeliveryThe delivery identifier, same value as delivery_id in the body
X-Webhook-SignatureHMAC-SHA256 of the raw body, hexadecimal

The signature covers the raw request body only (there is no timestamp component, unlike the inbound onboarding signature).

  1. Read the raw body bytes, before any JSON parsing.
  2. Compute HMAC-SHA256 of the body with the receiver’s secret and encode it in hexadecimal.
  3. Compare with X-Webhook-Signature using a constant time comparison.
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)

A delivery is successful when the receiver answers any 2xx status within 10 seconds. Otherwise the CMP retries:

AttemptDelay after the previous failure
2On the next drain after the failure
3At least 30 seconds after that

The outbox is drained by a job that runs every 60 seconds, so the drain interval dominates the real timing and the whole retry window is about two minutes. After the third failure the delivery is marked exhausted and is no longer retried automatically. Deliveries are persisted in an outbox before the first attempt, so a CMP restart never loses an event; the guarantee holds once the delivery row is written. Requeuing an exhausted delivery is a manual operation performed by Guardline operations on request, not a self-service API.

RequirementDetail
ProtocolHTTPS required
TLS version1.2 or higher
Success responseAny 2xx code, body ignored
TimeoutRespond within 10 seconds
IdempotencyDeduplicate on X-Webhook-Delivery (or delivery_id)

Receive the webhook, persist or enqueue it, and answer 200 immediately. Do the processing asynchronously.

Decisions on the Fraud and MED desks are recorded in the CMP with their justification, decision code and operational effects (cautionary hold, preventive account block, list additions) and are visible in the case detail and the audit trail of the console. The outbound webhook pipeline is shared by all desks, but no event is published for those desks at the moment; when the institution needs the fraud or MED outcome pushed to its core system, the subscription is enabled as part of the integration setup.

Tokens are managed by CMP administrators. The endpoints below require the console session cookie of a user with the admin role, which the AML director role inherits, so a AML director can manage tokens as well; they are not callable with an API token. The same operations are available in the console.

GET /api/v1/api-tokens

Returns every token with its label, prefix, scope, activity flag, rate limit, expiry, usage counter and last use. Token values are never returned.

POST /api/v1/api-tokens
{
"label": "fpp-producao",
"scope": "ingest:fraude",
"rate_limit_max": 300,
"rate_limit_window_seconds": 60,
"expires_in_days": 365
}
FieldRequiredDescription
labelyesDisplay name
scopenoOne of the scopes. Defaults to ingest
rate_limit_maxnoRequests per window. Defaults to 60
rate_limit_window_secondsnoWindow length. Defaults to 60
expires_in_daysnoDays until expiry. 0 or absent means no expiry

Response 201:

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

The token field appears only in this response. Store it in the secret vault of the source system immediately; it cannot be recovered later. If it is lost, create a new token and rotate.

Rotation without downtime: create the new token, configure it in the source system, confirm a successful ingest, then deactivate the old one.

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

Deactivation keeps the token record and its usage history for audit. A deactivated token answers 401 invalid api key and can be reactivated with is_active: true.

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

Deletion is permanent.

GET /api/v1/settings/webhooks

Returns the catalog of every inbound endpoint the instance exposes (the four ingest routes plus the communication provider callbacks for WhatsApp, SMS and voice), with the path, accepted methods, authentication type and header, and the required token scope. The catalog is derived from the route table of the running version, so it is the quickest way for an administrator to confirm the exact URL to hand to a source system.

StatusMeaning
200Request processed; the case already existed (idempotent replay, consolidation or reconciliation)
201Case created
400Malformed body or failed validation. Fix the request before retrying
401Missing or invalid API token, or failed HMAC signature
403Token scope does not cover the endpoint
404A referenced code does not exist (for example an unknown AML tipo_alerta)
409Conflict with the current state of the case
429Rate limit exceeded. Retry after the window
500Internal error. Retry with backoff and quote the request_id to support
503A dependency is unavailable. Retry with backoff
codeTypical statusDescription
BAD_REQUEST400A field failed validation; message says which
VALIDATION_ERROR400The body is empty or is not valid JSON
UNAUTHORIZED401Credential problem
FORBIDDEN403Scope problem
NOT_FOUND404Unknown reference code
CONFLICT409State conflict
DUPLICATE_EXTERNAL_ID409The ingest identifier was already used on that desk
ALREADY_EXISTS409The AML desk already holds an alert with that alerta_externo_id
RATE_LIMITED429Rate limit exceeded
SERVICE_UNAVAILABLE503Dependency unavailable
INTERNAL_ERROR500Unexpected failure

Recommended handling: treat 400, 401, 403 and 404 as permanent for that request (alert the operator, do not retry blindly); treat 429, 500 and 503 as transient (retry with exponential backoff, the idempotency keys make retries safe).

MethodPathAuthDescription
POST/api/v1/ingest/fraudeAPI token (ingest:fraude)Open a case on the Fraud desk
POST/api/v1/ingest/medAPI token (ingest:med)Open a case on the MED desk
POST/api/v1/ingest/pldAPI token (ingest:pld)Open or consolidate a case on the AML desk
POST/api/v1/ingest/kycAPI token (ingest:kyc) + optional HMACOpen or reconcile a case on the Cadastro PF or Cadastro PJ desk
GET/api/v1/api-tokensAdmin sessionList API tokens
POST/api/v1/api-tokensAdmin sessionCreate an API token
PATCH/api/v1/api-tokens/{id}/toggleAdmin sessionActivate or deactivate a token
DELETE/api/v1/api-tokens/{id}Admin sessionDelete a token
GET/api/v1/settings/webhooksAdmin sessionCatalog of inbound endpoints
GET/healthz, /readyz, /livezNoneLiveness and readiness probes

Version 18, updated on